用python编写Sebesda的词法分析器。不适用于输入fi中的最后一个词素

2024-09-27 00:22:54 发布

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

我必须把Sebesda的编程语言(第4章,第2节)中的代码翻译成python。以下是我目前所掌握的情况:

# Character classes #
LETTER = 0
DIGIT = 1
UNKNOWN = 99

# Token Codes #
INT_LIT = 10
IDENT = 11
ASSIGN_OP = 20
ADD_OP= 21
SUB_OP = 22
MULT_OP = 23
DIV_OP = 24
LEFT_PAREN = 25
RIGHT_PAREN = 26

charClass = ''
lexeme = ''
lexLen = 0
token = ''
nextToken = ''

### lookup - function to lookup operators and parentheses ###
###          and return the token                         ###
def lookup(ch):
    def left_paren():
        addChar()
        globals()['nextToken'] = LEFT_PAREN

    def right_paren():
        addChar()
        globals()['nextToken'] = RIGHT_PAREN

    def add():
        addChar()
        globals()['nextToken'] = ADD_OP

    def subtract():
        addChar()
        globals()['nextToken'] = SUB_OP

    def multiply():
        addChar()
        globals()['nextToken'] = MULT_OP

    def divide():
        addChar()
        globals()['nextToken'] = DIV_OP
    options = {')': right_paren, '(': left_paren, '+': add,
               '-': subtract, '*': multiply , '/': divide}

    if ch in options.keys():
        options[ch]()
    else:
        addChar()

### addchar- a function to add next char to lexeme ###
def addChar():
    #lexeme = globals()['lexeme']
    if(len(globals()['lexeme']) <=98):
        globals()['lexeme'] += nextChar
    else:
        print("Error. Lexeme is too long")

### getChar- a function to get the next Character of input and determine its character class ###
def getChar():
    globals()['nextChar'] = globals()['contents'][0]
    if nextChar.isalpha():
        globals()['charClass'] = LETTER
    elif nextChar.isdigit():
        globals()['charClass'] = DIGIT
    else:
        globals()['charClass'] = UNKNOWN
    globals()['contents'] = globals()['contents'][1:]


## getNonBlank() - function to call getChar() until it returns a non whitespace character ##
def getNonBlank():
    while nextChar.isspace():
        getChar()

## lex- simple lexical analyzer for arithmetic functions ##
def lex():
    globals()['lexLen'] = 0
    getNonBlank()
    def letterfunc():
        globals()['lexeme'] = ''
        addChar()
        getChar()
        while(globals()['charClass'] == LETTER or globals()['charClass'] == DIGIT):
            addChar()
            getChar()
        globals()['nextToken'] = IDENT

    def digitfunc():
        globals()['lexeme'] = ''
        addChar()
        getChar()
        while(globals()['charClass'] == DIGIT):
            addChar()
            getChar()
        globals()['nextToken'] = INT_LIT

    def unknownfunc():
        globals()['lexeme'] = ''
        lookup(nextChar)
        getChar()

    lexDict = {LETTER: letterfunc, DIGIT: digitfunc, UNKNOWN: unknownfunc}
    if charClass in lexDict.keys():
        lexDict[charClass]()
    print('The next token is: '+ str(globals()['nextToken']) + ' The next lexeme is: ' + globals()['lexeme'])

with open('input.txt') as input:
    contents = input.read()
    getChar()
    lex()
    while contents:
        lex()

我使用字符串sum + 1 / 33作为示例输入字符串。据我所知,在顶层对getChar()的第一次调用将characterClass设置为LETTER,contents设置为um + 1 / 33。在

然后程序进入while循环并调用lex()lex()依次将单词sum累加到lexeme。当letterfunc内的while循环遇到第一个空白字符时,它将中断,退出lex()

由于contents不是空的,程序将再次在顶层执行while循环。这一次,lex()中的getNonBlank()调用抛出了contents中的空格,并重复了与之前相同的过程。在

在我遇到错误的地方,是在最后一个词素。我被告知当getChar()调用时,globals()['contents'][0]超出范围。我不认为这是一个很难找到的错误,但我已经尝试了手工追踪,似乎找不到问题所在。任何帮助都将不胜感激。在


Tags: todefcontentsdigitoplexletterwhile
1条回答
网友
1楼 · 发布于 2024-09-27 00:22:54

这只是因为在成功地读取了输入字符串的最后一个3之后,digitfunc函数又重复了一次getchar。但此时content已耗尽且为空,因此{}被传递到缓冲区的末尾,因此出现错误。在

作为解决方法,如果在表达式的最后一个字符后添加换行符或空格,则当前代码不会出现问题。在

原因是,当最后一个字符是UNKNOWN时,您将立即从lex返回并退出循环,因为content为空,但是如果您正在处理一个数字或符号,则在不测试输入结尾的情况下循环调用getchar。顺便说一句,如果您的输入字符串以一个右paren结尾,lexer会吃掉它并忘记显示它找到了它。在

所以你至少应该:

  • getchar中输入的测试结束:

    def getchar():
        if len(contents) == 0:
            # print "END OF INPUT DETECTED"
            globals()['charClass'] = UNKNOWN
            globals()['nextChar'] = ''
            return
        ...
    
  • 显示最后一个标记(如果剩余):

    ...
    while contents:
        lex()
    lex()
    
  • 控制词素是否存在(在输入末尾可能会发生奇怪的事情)

    ...
    if charClass in lexDict.keys():
        lexDict[charClass]()
    if lexeme != '':
        print('The next token is: '+ str(globals()['nextToken']) +
              ' The next lexeme is: >' + globals()['lexeme'] + '<')
    

但是你对全局变量的使用是坏的。在函数中使用全局变量的常见习惯用法是在使用前声明它:

a = 5

def setA(val):
    global a
    a = val   # sets the global variable a

但是Python中的全局变量是代码气味。您所能做的最好的就是将解析器正确地封装在一个类中。对象比全局对象好

相关问题 更多 >

    热门问题