一个带有图形界面的C语言词法分析器,版本为Python2.7。
#!/usr/bin/python # -*- coding: utf-8 -*- import sys from Tkinter import * from tkFont import * from FileDialog import * KEYWORD_LIST = ['if', 'else', 'while', 'break', 'continue', 'for', 'double', 'int', 'float', 'long', 'short', 'bool', 'switch', 'case', 'return', 'void'] SEPARATOR_LIST = ['{', '}', '[', ']', '(', ')', '~', ',', ';', '.', '?', ':', ' '] OPERATOR_LIST = ['+', '++', '-', '--', '+=', '-=', '*', '*=', '%', '%=', '->', '|', '||', '|=', '/', '/=', '>', '<', '>=', '<=', '=', '==', '!=', '!', '&'] CATEGORY_DICT = { # KEYWORD "far": 257, "near": 258, "pascal": 259, "register": 260, "asm": 261, "cdecl": 262, "huge": 263, "auto": 264, "double": 265, "int": 266, "struct": 267, "break": 268, "else": 269, "long": 270, "switch": 271, "case": 272, "enum": 273, "register": 274, "typedef": 275, "char": 276, "extern": 277, "return": 278, "union": 279, "const": 280, "float": 281, "short": 282, "unsigned": 283, "continue": 284, "for": 285, "signed": 286, "void": 287, "default": 288, "goto": 289, "sizeof": 290, "volatile": 291, "do": 292, "if": 293, "while": 294, "static": 295, "interrupt": 296, "sizeof": 297, "NULL": 298, # SEPARATOR "{": 299, "}": 300, "[": 301, "]": 302, "(": 303, ")": 304, "~": 305, ",": 306, ";": 307, ".": 308, "#": 309, "?": 310, ":": 311, # OPERATOR "<<": 312, ">>": 313, "<": 314, "<=": 315, ">": 316, ">=": 317, "=": 318, "==": 319, "|": 320, "||": 321, "|=": 322, "^": 323, "^=": 324, "&": 325, "&&": 326, "&=": 327, "%": 328, "%=": 329, "+": 330, "++": 331, "+=": 332, "-": 333, "--": 334, "-=": 335, "->": 336, "/": 337, "/=": 338, "*": 339, "*=": 340, "!": 341, "!=": 342, "sizeof": 343, "<<=": 344, ">>=": 345, "inum": 346, "int16": 347, "int8": 348, "char": 350, "string": 351, "bool": 352, "fnum": 353, "IDN": 354 } current_row = -1 current_line = 0 out_line = 1 def getchar(input_str): global current_row global current_line current_row += 1 if current_row == len(input_str[current_line]): current_line += 1 current_row = 0 if current_line == len(input_str) - 1: return 'SCANEOF' return input_str[current_line][current_row] def ungetchar(input_str): global current_row global current_line current_row = current_row - 1 if current_row < 0: current_line = current_line - 1 current_row = len(input_str[current_row]) - 1 return input_str[current_line][current_row] def error(msg, line=None, row=None): global out_line if line is None: line = current_line + 1 if row is None: row = current_row + 1 analysis.insert(str(out_line) + '.0', str(line) + ':' + str(row) + 'Error: ' + msg) analysis.insert(str(out_line) + '.end', " ") out_line = out_line + 1 def scanner(input_str): global current_line global current_row current_char = getchar(input_str) if current_char == 'SCANEOF': return ('SCANEOF', '', '') if current_char.strip() == '': return if current_char.isdigit(): int_value = 0 while current_char.isdigit(): int_value = int_value * 10 + int(current_char) current_char = getchar(input_str) if current_char not in OPERATOR_LIST and current_char not in SEPARATOR_LIST and current_char != 'e': line = current_line + 1 row = current_row + 1 # ungetchar(input_str) error('illigal identifier', line, row) # return ('SCANEOF', '', '') return ('', '', '') if current_char != '.' and current_char != 'e': ungetchar(input_str) return ('INUM', int_value, CATEGORY_DICT['inum']) if current_char == 'e': power_value = str(int_value) + 'e' current_char = getchar(input_str) if current_char == '+' or current_char == '-': power_value += current_char current_char = getchar(input_str) while current_char.isdigit(): power_value += current_char current_char = getchar(input_str) if current_char not in OPERATOR_LIST and current_char not in SEPARATOR_LIST: line = current_line + 1 row = current_row + 1 # ungetchar(input_str) error('illigal const int value in power', line, row) # return ('SCANEOF', '', '') return ('', '', '') ungetchar(input_str) return ('INUM', power_value, CATEGORY_DICT['inum']) if current_char == '.': float_value = str(int_value) + '.' current_char = getchar(input_str) while current_char.isdigit(): float_value += current_char current_char = getchar(input_str) if current_char not in OPERATOR_LIST and current_char not in SEPARATOR_LIST or current_char == '.': line = current_line + 1 row = current_row + 1 # ungetchar(input_str) error('illigal const float value', line, row) # return ('SCANEOF', '', '') return ('', '', '') ungetchar(input_str) return ('FNUM', float_value, CATEGORY_DICT['fnum']) if current_char.isalpha() or current_char == '_': string = '' while current_char.isalpha() or current_char.isdigit() or current_char == '_' and current_char != ' ': string += current_char current_char = getchar(input_str) if current_char == 'SCANEOF': break ungetchar(input_str) if string in KEYWORD_LIST: return (string, '', CATEGORY_DICT[string]) else: return ('IDN', string, CATEGORY_DICT['IDN']) if current_char == '"': str_literal = '' line = current_line + 1 row = current_row + 1 current_char = getchar(input_str) while current_char != '"': str_literal += current_char current_char = getchar() if current_char == 'SCANEOF': error('missing terminating "', line, row) current_line = line current_row = row return ('SCANEOF', '', '') return ('STRING_LITERAL', str_literal, CATEGORY_DICT['string']) if current_char == '/': next_char = getchar(input_str) line = int(current_line) + 1 row = int(current_row) + 1 if next_char == '*': comment = '' next_char = getchar(input_str) while True: if next_char == 'SCANEOF': error('unteminated /* comment', line, row) return ('SCANEOF', '', '') if next_char == '*': end_char = getchar(input_str) if end_char == '/': return None if end_char == 'SCANEOF': error('unteminated /* comment', line, row) return ('SCANEOF', '', '') comment += next_char next_char = getchar(input_str) else: ungetchar(input_str) op = current_char current_char = getchar(input_str) if current_char in OPERATOR_LIST: op += current_char else: ungetchar(input_str) return ('OP', op, CATEGORY_DICT[op]) if current_char in SEPARATOR_LIST: return ('SEP', current_char, CATEGORY_DICT[current_char]) if current_char in OPERATOR_LIST: op = current_char current_char = getchar(input_str) if current_char in OPERATOR_LIST: op += current_char else: ungetchar(input_str) return ('OP', op, CATEGORY_DICT[op]) else: error('unknown character: ' + current_char) def fileloader(): global root code.delete(1.0, END) fd = LoadFileDialog(root) filename = fd.go() fin = open(filename, "r") input_file = fin.read() input_lines = input_file[0].split(" ") code.insert(1.0, input_file) fin.close() def lexer_analysis(input_str): global current_row global current_line global out_line current_row = -1 current_line = 0 analysis_result = [] while True: r = scanner(input_str) if r is not None: if r[0] == 'SCANEOF': break analysis_result.append(str(r[0]) + " " + str(r[1]) + " " + str(r[2])) return analysis_result def lexer(): input_str = [] analysis.delete(1.0, END) input_raw = code.get(1.0, END) input_str = input_raw.split(" ") lexer_analysis(input_str) out_line = 1 result = lexer_analysis(input_str) for each in result: analysis.insert(str(out_line) + '.end', each) analysis.insert(str(out_line) + '.end', " ") out_line = out_line + 1 def pre_interface(): global root global code global analysis root = Tk() code = Text(root, width=60, height=20, font=15) analysis = Text(root, width=60, height=20, font=15) t = StringVar() t.set('Patrick的词法分析器') label = Label(root, textvariable=t, font=15) Analysis = Button(root, text='词法分析', command=lexer, font=15) load = Button(root, text=' 载入代码 ', command=fileloader, font=15) root.title("LEXER") label.pack(side=TOP) Analysis.pack(side=BOTTOM) load.pack(side=BOTTOM) code.pack(side=LEFT) analysis.pack(side=RIGHT) root.mainloop() def main(): pre_interface() # lexer() if __name__ == '__main__': main()