自制Python编译器词法分析将符号识别为换行问题求助
问题原因分析
你遇到的异常是两个问题共同导致的:
- 第一个是明确的语法错误:你定义的
LETTER数组中,大写字母'M'的末尾缺少逗号,Python会自动拼接相邻的字符串字面量,导致'M'和下一行开头的'N'被合并为'MN'存入数组。这会导致大写字母列表缺失单独的'M'和'N',后续识别包含大写M、N的标识符时会出错。 - 第二个是你当前异常输出的核心原因:你使用文本模式打开文件,Python的文本模式会自动对不同平台的换行符做转换(比如Windows下
\r\n会被转换为\n),但seek()和tell()操作的是文件的原始字节偏移,而非转换后的字符位置。你在识别标识符的逻辑中执行input_file.seek(input_file.tell() - 1)时,偏移计算可能出现错位,导致回退后没有指向预期的;符号,反而指向了换行符的字节位置,所以下次读取字符时拿到的是换行而非分号,表现为分号被当成了换行处理。
你在prod和;之间加空格、多加分号等操作能恢复正常,是因为这些场景下回退的偏移位置刚好对齐了单字节字符的边界,没有触发换行转换的偏移错位问题。
修复方案
- 先修复
LETTER数组的语法错误,在大写'M'后面补充逗号:
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 = [';', ':', ',', '[', ']', '{', '}', '(', ')', '+', '-', '*', '=', '<'] # 替换原有的文件打开和读取逻辑 with open('input.txt', 'r', encoding='utf-8') as f: content = f.read() ptr = 0 line_num = 1 def get_token(): global ptr, line_num if ptr >= len(content): return None value = content[ptr] ptr += 1 if value in WHITESPACE: start = line_num if value == '\n': line_num += 1 return "whitespace", value, start elif value in LETTER: while ptr < len(content): input_char = content[ptr] ptr +=1 if input_char in LETTER: value += input_char elif input_char in SYMBOL or input_char in WHITESPACE: ptr -=1 return 'id', value, line_num else: value += input_char return 'invalid', value, line_num return 'id', value, line_num elif value in SYMBOL: return 'symbol', value, line_num else: return 'invalid', value, line_num # 调用逻辑不变 while True: token = get_token() if token: print(f"({token[2]}, {token[0]}, {token[1]})") else: break
内容的提问来源于stack exchange,提问作者negar.n
相关产品推荐
相关产品推荐

