使用Sly库时遭遇未使用规则及语法错误问题求助
解决Sly库中未使用规则及语法错误问题
问题现象
运行代码后收到大量未使用规则警告,执行命令时还会抛出语法错误:
警告: C:\Program Files\adbms\strg_eng\done.py:66: 已定义规则'change_tname'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:70: 已定义规则'create_db'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:74: 已定义规则'create_tb'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:78: 已定义规则'sort'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:82: 已定义规则'delete_db'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:86: 已定义规则'delete_tb'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:90: 已定义规则'delete_rec'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:94: 已定义规则'delete_column'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:98: 已定义规则'create_column'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:102: 已定义规则'create_rec'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:106: 已定义规则'display_tb'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:110: 已定义规则'update_c'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:114: 已定义规则'update_r'但未使用 警告: C:\Program Files\adbms\strg_eng\done.py:118: 已定义规则'get_list'但未使用 警告: 存在14条未使用规则 警告: 符号'change_tname'不可达 警告: 符号'create_db'不可达 警告: 符号'create_tb'不可达 警告: 符号'sort'不可达 警告: 符号'delete_db'不可达 警告: 符号'delete_tb'不可达 警告: 符号'delete_rec'不可达 警告: 符号'delete_column'不可达 警告: 符号'create_column'不可达 警告: 符号'create_rec'不可达 警告: 符号'display_tb'不可达 警告: 符号'update_c'不可达 警告: 符号'update_r'不可达 警告: 符号'get_list'不可达 FileLang> create_db test_tb sly: 第1行语法错误,令牌=CREATE_DB
问题原因
- 缺少起始规则:Sly Parser要求必须有一个起始规则,所有其他语法规则都要能被起始规则关联。当前代码中的命令规则都是独立的,没有被任何起始规则引用,导致Parser无法识别,标记为未使用/不可达。
- Tokens集合不完整:Lexer中定义的
NUMBER和TEXT方法没有加入tokens集合,可能导致数值和文本类型的token无法被正确识别。 - Token匹配冲突:
MIN、MAX的正则表达式[0-9]+和NUMBER规则重复,Sly按定义顺序优先匹配,会导致数值被错误识别为MIN/MAX而非NUMBER。
解决方案
- 添加起始规则:定义
statement作为起始规则,将所有命令规则作为它的备选项,让Parser能遍历到所有命令。 - 完善Tokens集合:将
NUMBER和TEXT加入Lexer的tokens集合。 - 调整Token匹配逻辑:删除
MIN、MAX的单独定义,在语法规则中直接使用NUMBER(MIN/MAX本质就是数值),避免匹配冲突。
修改后的完整代码
from sly import Lexer, Parser from drm import * # Import everything from the drm module # Lexer class FileLexer(Lexer): tokens = {CREATE_DB, CREATE_TB, CREATE_REC, CREATE_COLUMN, DELETE_DB, DELETE_TB, DELETE_REC, DELETE_COLUMN, CHANGE_DBNAME, CHANGE_TNAME, SORT, DISPLAY_TB, UPDATE_C, UPDATE_R, GET_LIST, COLUMN_NAME, VALUE, TYPE, CONSTRAINT, DBNAME, TNAME, NEWNAME, NUMBER, TEXT} ignore = ' \t\n' # 关键字优先定义 CREATE_DB = r'create_db' CREATE_TB = r'create_tb' CREATE_REC = r'create_rec' CREATE_COLUMN = r'create_column' DELETE_DB = r'delete_db' DELETE_TB = r'delete_tb' DELETE_REC = r'delete_rec' DELETE_COLUMN = r'delete_column' CHANGE_DBNAME = r'change_dbname' CHANGE_TNAME = r'change_tname' SORT = r'sort' DISPLAY_TB = r'display_tb' UPDATE_C = r'update_c' UPDATE_R = r'update_r' GET_LIST = r'get_list' TYPE = r'(st|num)' CONSTRAINT = r'(NONE|NOTNONE|UNIQUE|NOUNI)' DBNAME = r'[a-zA-Z0-9_.-]+' TNAME = r'[a-zA-Z0-9_.-]+' NEWNAME = r'[a-zA-Z0-9_.-]+' COLUMN_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' VALUE = r'[a-zA-Z_0-9]+' # 数值和文本定义放在后面,避免和关键字冲突 @_(r'[0-9]+') def NUMBER(self, t): t.value = int(t.value) return t @_(r'"[^"]*"') def TEXT(self, t): t.value = t.value.strip('"') return t def error(self, t): print(f'Illegal character {t.value[0]} at line {self.lineno}') self.index += 1 # Parser class FileParser(Parser): tokens = FileLexer.tokens # 指定起始规则 start = 'statement' def __init__(self): self.symbol_table = {} # 起始规则,包含所有命令选项 @_('change_dbname', 'change_tname', 'create_db', 'create_tb', 'sort', 'delete_db', 'delete_tb', 'delete_rec', 'delete_column', 'create_column', 'create_rec', 'display_tb', 'update_c', 'update_r', 'get_list') def statement(self, p): pass @_('CHANGE_DBNAME DBNAME NEWNAME') def change_dbname(self, p): print(f'Change DB Name: {p.DBNAME} to {p.NEWNAME}') @_('CHANGE_TNAME DBNAME TNAME NEWNAME') def change_tname(self, p): print(f'Change Table Name: {p.DBNAME} {p.TNAME} to {p.NEWNAME}') @_('CREATE_DB DBNAME') def create_db(self, p): print(f'Create DB: {p.DBNAME}') @_('CREATE_TB DBNAME TNAME') def create_tb(self, p): print(f'Create Table: {p.DBNAME} {p.TNAME}') @_('SORT DBNAME TNAME') def sort(self, p): print(f'Sort: {p.DBNAME} {p.TNAME}') @_('DELETE_DB DBNAME') def delete_db(self, p): print(f'Delete DB: {p.DBNAME}') @_('DELETE_TB DBNAME TNAME') def delete_tb(self, p): print(f'Delete Table: {p.DBNAME} {p.TNAME}') @_('DELETE_REC DBNAME TNAME') def delete_rec(self, p): print(f'Delete Record: {p.DBNAME} {p.TNAME}') @_('DELETE_COLUMN DBNAME TNAME COLUMN_NAME') def delete_column(self, p): print(f'Delete Column: {p.DBNAME} {p.TNAME} {p.COLUMN_NAME}') # 将MIN/MAX替换为NUMBER @_('CREATE_COLUMN DBNAME TNAME COLUMN_NAME TYPE NUMBER NUMBER CONSTRAINT') def create_column(self, p): print(f'Create Column: {p.DBNAME} {p.TNAME} {p.COLUMN_NAME} {p.TYPE} {p.NUMBER0} {p.NUMBER1} {p.CONSTRAINT}') @_('CREATE_REC DBNAME TNAME') def create_rec(self, p): print(f'Create Record: {p.DBNAME} {p.TNAME}') @_('DISPLAY_TB DBNAME TNAME') def display_tb(self, p): print(f'Display Table: {p.DBNAME} {p.TNAME}') @_('UPDATE_C DBNAME TNAME COLUMN_NAME VALUE') def update_c(self, p): print(f'Update Column: {p.DBNAME} {p.TNAME} {p.COLUMN_NAME} {p.VALUE}') @_('UPDATE_R DBNAME TNAME COLUMN_NAME VALUE') def update_r(self, p): print(f'Update Record: {p.DBNAME} {p.TNAME} {p.COLUMN_NAME} {p.VALUE}') @_('GET_LIST DBNAME TNAME COLUMN_NAME') def get_list(self, p): print(f'Get List: {p.DBNAME} {p.TNAME} {p.COLUMN_NAME}') # Example usage if __name__ == '__main__': lexer = FileLexer() parser = FileParser() while True: try: text = input('FileLang> ') tokens = lexer.tokenize(text) parser.parse(tokens) except EOFError: break
说明
- 新增
start = 'statement'指定起始规则,statement规则包含所有命令作为备选项,解决了规则不可达的问题。 - 将
MIN、MAX从tokens中移除,改用NUMBER匹配数值,避免了token冲突。 - 修正
TEXT的正则表达式,直接用"[^"]*"并处理去掉引号的逻辑,更符合实际使用场景。 - 将
NUMBER和TEXT加入tokens集合,确保能被正确识别。
内容的提问来源于stack exchange,提问作者METTALIC STAR
相关产品推荐
相关产品推荐

