Pelco KBD300A 模拟器:第7篇. 宏脚本编辑器设计与解释器实现

第7篇. 宏脚本编辑器设计与解释器实现

引言

在上篇键盘优化子系列中,我们完成了左侧 UI 的全面完善,包括布局、按键和反馈机制,为模拟器注入了真实的操作手感。现在,随着项目从键盘复刻转向完整维护工具,我们引入宏系统:一种自定义脚本机制,用于自动化巡航、报警联动和调试场景。本篇文章将深入宏系统的设计与实现,从语法定义到解释器执行,比较单文件版(无宏,仅基本命令)与最终版的完整引擎(core/macro/)。宏的作用在于简化重复操作(如循环调用预置位),回顾 UI:键盘的模式切换(如 "MACRO")可触发宏编辑面板。这一功能基于 Python 3.7 和 PyQt5,确保 Windows 7 下的线程安全执行。让我们探索从 parser 到 engine 的全链路。

宏示例:cruise_alarm.macro 的 loop/delay/send_preset,展示了巡航 + 报警联动的实用性。

🧬 语法设计

宏语法简单却强大,支持 loop/for 循环、delay 延时、command(如 send_preset/aux_on)和变量(符号表)。设计原则:易学(类似简化 Lua),针对安防场景(预置位/辅助开关)。示例 cruise_alarm.macro:

  • loop(2){ send_preset(1,1); delay(3000); ... } # 循环巡航
  • aux_on(1,1); delay(2000); # 报警联动

单文件版无宏(命令硬编码);最终版用 AST 表示语法树,便于扩展(未来加 IF/ELSE)。

代码示例(从最终代码提取)

python 复制代码
# 从 resources/macros/cruise_alarm.macro(示例语法)
loop(2){
    send_preset(1, 1)
    delay(3000)
    # ... (预置位 2-4)
}
aux_on(1, 1)
delay(2000)

这一设计强调可读性,参数用 {{}} 支持模板化。

🔍 Lexer/Parser

Lexer 将脚本 token 化(e.g., integer/ID/LOOP),Parser 构建 AST(Compound/Loop/For/Command)。Token 类型包括 INTEGER/ID/LPAREN 等。过程:advance 跳字符,eat 消费 token,parse() 递归构建树。

对比单文件版:无解析(直接函数调用);最终版支持错误处理(self.error("Invalid expr"))。

代码示例(从最终代码提取)

python 复制代码
# 从 core/macro/parser.py(Lexer 示例)
class Lexer:
    def integer(self):
        result = ''
        while self.current_char is not None and self.current_char.isdigit():
            result += self.current_char
            self.advance()
        return Token(INTEGER, int(result))

# Parser 示例(构建 Loop)
def loop(self):
    self.eat(LOOP)
    self.eat(LPAREN)
    count = self.expr()  # 循环次数
    self.eat(RPAREN)
    self.eat(LBRACE)
    body = self.compound()
    self.eat(RBRACE)
    return Loop(count, body)

# 单文件版对比:无宏,建议"早期原型无宏,后扩展为 engine"

🚀 解释器

MacroEngine 是执行核心:visit() 递归遍历 AST(_visit_loop 执行 count 次 body)。线程化:moveToThread(macro_thread),run() 在子线程。支持进度(_update_progress emit)和停止(_running=False)。

对比单文件版:无解释器;最终版用 _symbol_table 处理变量,_eval 评估 expr。

代码示例

python 复制代码
# 从 core/macro/engine.py(解释器执行)
def _visit_loop(self, node):
    count = self._eval(node.count)
    for _ in range(count):
        if not self._running:
            return
        self._visit(node.body)
        self._update_progress()  # 进度 emit

# 线程化
self.macro_engine.moveToThread(self.macro_thread)
self.macro_thread.started.connect(self.macro_engine.run)

🔧 UI 编辑器

macro_editor.py 用 QsciScintilla(QsciLexerLua 高亮)实现编辑,支持保存/删除。新/运行按钮连接 load_template/run_macro emit。进度条(set_progress)实时反馈。

集成:main_window.py 的 self.macro_engine.started.connect(self.right.set_progress(0))。

代码示例

python 复制代码
# 从 ui/right_panel/macro_editor.py(UI 编辑器)
self.editor = QsciScintilla()
lexer = QsciLexerLua(self.editor)
self.editor.setLexer(lexer)  # 高亮
self.run_btn.clicked.connect(self._run)  # emit run_macro

🔗 集成

main_window.py 用 self.macro_engine 连接 UI:_run_macro(script) set_script + run。键盘 "MACRO" 模式 tabs.setCurrentWidget(macro_editor)。

🛡️ 调试

错误处理:parse_macro_script 捕获 ValueError emit error。符号表 (_symbol_table) 调试变量(logger.info)。线程异常用 logger.exception。

对比单文件版:无调试;最终版支持。

🏁 结尾

通过本篇,我们完成了宏编辑器与解释器的设计与实现,将模拟器从静态键盘扩展到自动化工具。这一功能突显了 AST 的可扩展性(未来 IF)。下一篇文章《7.5 Python 专题:线程安全与信号槽机制》将深入探讨宏/串口的并发优化。欢迎在评论区分享你的宏语法设计想法!

基于 Python 3.7(Windows 7)开发 Pelco KBD300A 模拟器兼 Pelco-D / Pelco-P 协议现场维护工具.

上一篇 总目录 下一篇

相关推荐
智源研究院官方账号8 小时前
众智FlagOS 1.6发布,以统一架构推动AI硬件、软件技术生态创新发展
数据库·人工智能·算法·架构·编辑器·硬件工程·开源软件
Mqh1807628 小时前
day61 经典时序模型3
python
我想吃烤肉肉8 小时前
logger比print优秀之处
python
Cosmoshhhyyy8 小时前
《Effective Java》解读第32条:谨慎并用泛型和可变参数
java·python
Cherry的跨界思维9 小时前
【AI测试全栈:Vue核心】19、Vue3+ECharts实战:构建AI测试可视化仪表盘全攻略
前端·人工智能·python·echarts·vue3·ai全栈·ai测试全栈
leiming69 小时前
c++ QT 开发第二天,用ui按钮点亮实体led
开发语言·qt·ui
海棠AI实验室9 小时前
第十七章 调试与排错:读懂 Traceback 的方法论
python·pandas·调试
2501_941878749 小时前
在奥克兰云原生实践中构建动态配置中心以支撑系统稳定演进的工程经验总结
开发语言·python
Rabbit_QL9 小时前
【Pytorch使用】CUDA 显存管理与 OOM 排查实战:以 PyTorch 联邦学习训练为例
人工智能·pytorch·python
weixin_443297889 小时前
Python打卡训练营第31天
开发语言·python