【问题标题】:program reads character as newline程序将字符读取为换行符
【发布时间】:2021-10-20 06:00:24
【问题描述】:

我有一个我一直在制作的编译器代码的简化版本,一个奇怪的事件让我感到困惑。这是简化的代码:

LETTER = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
          'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'
          'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
          'X', 'Y', 'Z']

WHITESPACE = [' ', '\n', '\r', '\v', '\t', '\f']

SYMBOL = [';', ':', ',', '[', ']', '{', '}', '(', ')', '+', '-', '*', '=', '<']

input_file = open('input.txt', 'r')
line_num = 1

def get_token():
    global line_num

    value = ''
    input_char = ''

    value = input_file.read(1)

    if value in WHITESPACE:
        start = line_num
        if value == '\n':
            line_num += 1
        return "whitespace", value, start
    
    elif value in LETTER:
        input_char = input_file.read(1)
        while input_char != '':
            if input_char in LETTER:
                value += input_char
            elif input_char in SYMBOL or input_char in WHITESPACE:
                input_file.seek(input_file.tell() - 1)
                return 'id', value, line_num
            else:
                value += input_char
                return 'invalid', value, line_num
            input_char = input_file.read(1)
        return 'id', value, line_num
    elif value in SYMBOL:
        return 'symbol', value, line_num
    elif value == '':
        return None
    else:
        return 'invalid', value, line_num
        


while True:
    token = get_token()
    if token:
        print(f"({token[2]}, {token[0]}, {token[1]})")
    else:
        break

input_file.close()

这是输入文件的内容:

prod;

}

这是我想要实现的输出:

(1, id, prod)
(1, symbol, ;)
(1, whitespace, 
)
(2, whitespace, 
)
(3, symbol, })

但是,这是我得到的输出:

(1, id, prod)
(1, whitespace, 
)
(2, whitespace, 
)
(3, whitespace, 
)
(4, symbol, })

在检查每个阶段的变量值和文件指针后,我得出的结论是程序确实在识别字符';'作为换行符,我放在它的位置的任何其他符号也是如此。更令人困惑的是,如果我把拳头写成 'prod ;'或“产品;;”的'产品; ' 它给出了正确的输出。这是怎么回事?

【问题讨论】:

  • 不相关:from string import ascii_letters, whitespace - punktuation 不太合适。
  • @PatrickArtner 问题是我不允许使用任何导入的库
  • 我试过你的代码,它给了我你想要的输出(嗯,几乎,最后有额外的空格)。检查您的输入文件。

标签: python compiler-construction character newline


【解决方案1】:

您似乎在未提及的约束下工作(即评论中的“问题是我不允许使用任何导入的库”)。

你的寻求并不像你那样工作。不要使用tell,而是自己跟踪位置:

pos = 0

# handle your own positioning    
def get_char_and_pos(f):
    """Reads one character from file, returns character and position"""
    global pos
    pos += 1
    return f.read(1), pos-1

并通过调用您的位置跟踪函数替换所有 input_file.read(1) 实例:

# sets are faster for 'in' checks
LETTER = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
WHITESPACE = set(" \n\r\v\t\f")
SYMBOL = set(";:,[]{}()+-*=<")

# write demo file
with open("input.txt", "w") as f:
    f.write("prod;\n\n}") 

input_file = open('input.txt', 'r+')
line_num = 1

def get_token():
    global line_num

    value = ''
    input_char = ''

    value, value_pos = get_char_and_pos(input_file)    # use function 

    if value in WHITESPACE:
        start = line_num
        if value == '\n':
            line_num += 1
        return "whitespace", value, start
    
    elif value in LETTER:
        input_char, value_pos = get_char_and_pos(input_file)   # use function 
        while input_char != '':
            if input_char in LETTER:
                value += input_char
            elif input_char in SYMBOL or input_char in WHITESPACE:
                input_file.seek(value_pos)      # jump to correct position
                return 'id', value, line_num
            else:
                value += input_char
                return 'invalid', value, line_num
            input_char, value_pos = get_char_and_pos(input_file)  # use function 
        return 'id', value, line_num
    elif value in SYMBOL:
        return 'symbol', value, line_num
    elif value == '':
        return None
    else:
        return 'invalid', value, line_num
        


while True:
    token = get_token()
    if token:
        print(f"({token[2]}, {token[0]}, {token[1]})")
    else:
        break

input_file.close()

输出:

(1, id, prod)
(1, symbol, ;)  
(1, whitespace, 
)
(2, whitespace, 
)
(3, symbol, })  

【讨论】:

  • 非常感谢您的帮助。你知道为什么tell 不能按我想要的方式工作吗?
  • @negar.n 不确定 - tell() 在文本文件上很奇怪。见here - 大约 2/3:一点见解tell() + 文本文件。实际上,您可能有 f.e. \r\n 在你的文件中(windows 风格的行尾),但是当 read() 你的字符串只包含 \n - \r 被python剥离,所以你只剩下 \n 了。然后是 utf-8 编码,有时字符编码为 2 个字节而不是 1 个字节,这可能会使定位变得不稳定(afaics 你不使用 utf8,但 *shrug*)。我第一次尝试tell(-1,1) - 但在文本文件中出现了其他问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-22
  • 2014-01-16
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
  • 2018-05-10
相关资源
最近更新 更多