百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

如何编写基于窗口的脚本解释程序_如何编写基于窗口的脚本解释程序

liuian 2025-08-31 03:59 7 浏览

今天一时兴起,利用已有控件写了一个基于窗口,语法高亮显示的 Lysee 脚本解释程序,借此文章分享一下具体的开发的过程。

一、简要说明

这个程序长这个样子,名字暂定为 laoke 唠嗑的意思,下面是这个程序的第一张截图,后续会把这个程序的源代码上传到 gitee 上(
https://gitee.com/lysee/lysee.git)。

相比下面这种长期使用的 console 版本,由于语法加亮,感觉舒爽多了。

二、开发过程

1.选择适宜的语法加亮编辑器

这里选择使用 TLyCodeMemo,这个编辑器使用在 lwrite 程序中,是 Lysee 套件的一部分。当然也可以选择使用 Lazarus 自带的 TSynEdit,基本原理是一样的。

2.建立规则

  1. 为编辑器建立终端录入模式。
  2. 只有在编辑器最后一行时才允许修改、剪切、粘贴。
  3. 增加 write 函数,让解释程序可以向编辑器写入文本,像 stream 一样追加到文档尾部。
  4. 记录 write 函数写入后,最后一行的位置,在这个位置之前不允许修改任何内容。
  5. 修改编辑器对回车换行的处理,在最后一行回车时将回车位置前的实际输入内容回传给解释程序执行。解释程序执行完毕后,再向编辑器写入输入提示符。
  6. 如此循环往复,完成交互过程。

3.编写代码

3.1 为编辑器增加中断模式和 write 函数,记录写入情况:

procedure TLyCodeMemo.Write(const S: string);

var

W: WideString;

begin

if not (msTerminal in FState) then Exit; // 新增的 msTerminal 状态

{$IFDEF UNICODE}

W := S;

{$ELSE}

W := UTF8Decode(S);

{$ENDIF}

FSelection.UnSelect;

FCaret.MoveToTail(FLines.Last);

FSelection.SetText(W);

FCaret.MoveToTail(FLines.Last);

FWriteCount := Length(FLines.Last.Text);

end;

3.2 检测选择内容和位置是否只读,只读时禁止录入。

function TLySelection.GetReadonly: boolean;

var

L, M: TLyLine;

begin

Result := FMemo.Readonly or (FMemo.Terminal and FSelectAll);

if not Result and FMemo.Terminal then

begin

L := FMemo.Lines.Last;

if Selected then

begin

M := FMemo.FLines[FHead.ItemX];

Result := (M <> L) or (FHead.TextX < FMemo.FWriteCount);

end

else

begin

M := FMemo.FCaret.GetItem;

Result := (M <> L) or (FMemo.FCaret.FPos.TextX < FMemo.FWriteCount);

end;

end;

end;

3.3 接管编辑器回车换行处理

if (Key = #10) or (Key = #13) then

begin

H := (msTerminal in FState) and (FCaret.Item = FLines.Last) and Assigned(FOnInput);

if H then

begin

N := FWriteCount;

L := FLines.Last;

end;

FSelection.SetText(sLineBreak);

if H then

begin

if N > 0 then

C := Copy(L.FText, N + 1, Length(L.FText)) else

C := L.FText;

L := FLines.Last;

W := L.FText;

L.SetText('');

FWriteCount := 0;

FOnInput(Self, WideToStr(C));

L := FLines.Last;

L.SetText(L.FText + W);

FCaret.MoveDocumentEnd;

end;

end

编辑器通过 FOnInput 回调函数向解释程序传送代码。

3.4 解释程序执行代码

procedure TLaokeForm.OnInput(Sender: TObject; const S: string);

function match_head(const S: string; const IDs: array of string): boolean;

var

I: integer;

begin

Result := false;

for I := 0 to Length(IDs) - 1 do

if LyMatchID(IDs[I], Copy(S, 1, Length(IDs[I]))) then

begin

Result := true;

Exit;

end;

end;

function match_fp(const S: string): boolean;

begin

Result := match_head(S, ['function', 'procedure', 'def'])

end;

procedure do_execute(const code: string);

var

V: PLyValue;

N: int64;

begin

try

if code <> '' then

begin

N := FEngine.WriteCount;

if FEngine.Execute(code) then

begin

if N <> FEngine.WriteCount then

if not CharInSet(FEngine.LastWritenChar, [#10, #13]) then

FEngine.Writeln;

V := FEngine.MainThread.Result;

if V^.v_type <> my_nil then

begin

Writeln('--> ' + LyFormatValue(V));

LySetNil(V);

end;

end;

end;

finally

FScript := '';

end;

end;

var

T: string;

L: TLyLine;

begin

if FWaitForInput then

begin

FScript := '';

FInputText := S;

FWaitForInput := false;

Exit;

end;

T := TrimRight(S);

if LyMatchID(Copy(T, 1, 3), ['>>>', ' >']) then

T := Copy(T, 5, Length(T));

if T = '' then do_execute(FScript) else

begin

if LyMatchID('quit', T) then Close else

if FScript <> '' then

FScript := FScript + sLineBreak + T else

if T <> '' then

if (T[Length(T)] <> ';') or match_fp(Trim(T)) then

FScript := T else

do_execute(T);

end;

FInput.UnSelect;

L := FInput.Lines.Last;

if Trim(L.Text) = '' then

begin

if FScript = '' then

L.Text := '>>> ' else

L.Text := ' > ';

end

else

begin

T := WideToStr(L.Text);

if not LyMatchID(T, ['>>> ', ' > ']) then

if FScript = '' then

FInput.Lines.Add('>>> ') else

FInput.Lines.Add(' > ');

end;

FInput.Write('');

end;

3.5 将执行程序 readln 过程委托给编辑器完成

在程序中增加以下状态变量,用于等级输入状态和输入结果

FWaitForInput: boolean;

FInputText: string;

建立 OnReadln 回调函数,在执行程序和编辑器中间建立起联系:

FEngine := TLysee.Create(Self);

FEngine.OnWrite := @OnWrite;

FEngine.OnError := @OnError;

FEngine.OnReadln := @OnReadln;

end;


procedure TLaokeForm.OnReadln(Sender: TObject; var S: string);

begin

FWaitForInput := true;

FInputText := '';

while FWaitForInput do

begin

Application.ProcessMessages;

Sleep(1);

end;

S := FInputText;

end;

当编辑器调用 FOnInput 回调函数时完成输入:

procedure TLaokeForm.OnInput(Sender: TObject; const S: string);

begin

if FWaitForInput then

begin

FScript := '';

FInputText := S;

FWaitForInput := false;

Exit;

end;

.................

end;

end;

大概就是这个过程,不是很复杂,使用其他语法高亮控件应该也能同样原理实现。

开始觉得很难,想着试试算了,没想到真上手一天就全部搞定了。

希望对伙计们能有一些帮助。


说明:Lysee 是本人因以往工作经历和个人爱好开发并维护的一个脚本编程语言,延用 MODIFIED BSD 许可协议,大家可以自由下载使用,但要自行承担风险。Lysee 使用树形结构解析并执行代码,所以执行速度一般,但优势是可以根据需要做语法扩展,扩展方法也很简单,特别适合嵌入 Lysee 实现特定功能地场合。

相关推荐

python环境怎么搭建?小白看完就会!简简单单

很多小伙伴安装了python不会搭建环境,看完这个你就会了Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否...

手把手教本地部署Xinference + deepseek-R1、reranker-v2、bge-m3

Xinference作为本地AI推理框架,相较于Ollama和其他推理方案,有以下几个核心优势:1.多模型支持。Xinference兼容大量LLM(大语言模型),不仅支持LLaMA...

Windows 10下使用编译并使用openCV

1.Windows系统下OpenCV及第三方库文件的使用与下载如果没有特殊要求,在Windows系统下可以直接使用OpenCV的预编译版本。在github的opencv项目release中选择相应r...

Windows环境CMake学习笔记(一)_windows下cmake使用

前言CMake是C++的必学部分,本篇文章从安装环境开始,通过使用CMake构建一个最简单的cpp项目和g++直接编译作对比了解CMake的构建过程,为接下来深入学习CMake打下基础。一、系统环境操...

Docker 安装教程_docker安装shinobi

Docker概述与安装&Dockerfile文件一、Docker概述Docker是一个开源的容器化平台,它允许开发者将应用及其依赖打包到轻量级、可移植的容器中,并能在任何支持Docker...

【直播流】RTSP拉流转推RTMP_rtmp推流和rtsp拉流区别

背景:从第三方协调了几路慢直播,直播流的协议有RTSP、FLV和HLS。不过,本方播放工具只能稳定地播放RTMP流。(本次测试环境:Windows10)步骤概述:安装FFmpeg,用于拉流和转码推流。...

Windows常用的一些CMD运行命令_windows使用cmd运行程序

CMD命令:开始->运行->键入cmd或command(在命令行里可以看到系统版本、文件系统版本appwiz.cpl:程序和功能calc:启动计算器certmgr.msc:证书管理实...

JAVA编程环境搭建 JDK与环境变量、Eclipse

1JDK1.1JDK概述JDK是Java语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了:JAVA开发工具(jdk\bin)基础...

go os/exec 简明教程_go语言os包

Go标准库提供了便利的方法,可以很容易地运行外部命令,一般我们会使用os/exec包下的方法实现执行外部命令以及和外部命令交互。os/exec包装了os.StartProcess方法,更方便的进行输入...

Python内置模块:shutil模块使用教程(文件与目录高级操作实践)

一、shutil模块简介在Python开发中,文件与目录操作是最基础的需求之一。虽然os模块提供了基础的文件系统交互能力,但对于复制、移动、删除目录、归档压缩等复杂操作,shutil模块(Shell...

乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现

|注:本文曾发表在博客园我的个人博客中,转载至此公众号以归档保存。家里小朋友养了一只小乌龟,到了冬天就冬眠了,早早地准备了一个冬眠箱,铺上椰土,在室温低于15℃时,就把小乌龟放到冬眠箱里,不一会儿它...

Python环境安装教程_python安装及环境变量配置

文章目录前言一、安装python运行环境1.官网https://www.python.org下载安装包.exe2.安装python二、python模块下载1.配置pip环境变量2.下载pyth...

Python Windows 11 安装后,CMD界面进入不了Python编译界面的解决

1.Python安装进入官网下载python编译界面PythonReleasePython3.10.4|Python.org2.搜索栏输入cmd,进入命令提示符这时输入python命令提...

Windows命令行command的Shell命令详细解析和语法

CMD命令大全及详细解释和语法CMD命令大全及详细解释和语法MicrosoftWindowsXP[版本5.1.2600]有关某个命令的详细信息,请键入HELP命令名ASSOC显示或修改文...

JDK1.8安装&amp;环境变量配置_java安装jdk配置环境变量

1、下载并安装JDK1.8链接:https://pan.baidu.com/s/1bfceFjfTQvLylu7a3T7fyg?pwd=ydtm提取码:ydtm2、设置环境变量2.1打开“控制面板”...