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

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

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

今天一时兴起,利用已有控件写了一个基于窗口,语法高亮显示的 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 实现特定功能地场合。

相关推荐

windows2003镜像32位下载(win2003系统镜像)

虚拟光驱装系统,(win7,xp通用)具体步骤一、将从网上下载的win7旗舰版ISO系统文件存放到D盘。二、从网上下载虚拟光驱,打开安装后在任务栏右通知区显示“虚拟DAEMON管理器”图标,在我的电脑...

如何制作表格excel工作表(如何制作表格excel工作表表头)
  • 如何制作表格excel工作表(如何制作表格excel工作表表头)
  • 如何制作表格excel工作表(如何制作表格excel工作表表头)
  • 如何制作表格excel工作表(如何制作表格excel工作表表头)
  • 如何制作表格excel工作表(如何制作表格excel工作表表头)
win10电脑自动更新怎么关闭(win10电脑怎么关闭自动更新系统)

win10老推送win11打开的方法步骤如下,1,首先,打开设置,点击更新和安全2,打开后,点击windows预览体验计划3,打开后,点击开始4,然后按流程进行注册5,注册完成后,点击选择帐户6,然后...

电脑如何下载打印机驱动并安装
  • 电脑如何下载打印机驱动并安装
  • 电脑如何下载打印机驱动并安装
  • 电脑如何下载打印机驱动并安装
  • 电脑如何下载打印机驱动并安装
微软售后维修点(微软售后维修点江门)
  • 微软售后维修点(微软售后维修点江门)
  • 微软售后维修点(微软售后维修点江门)
  • 微软售后维修点(微软售后维修点江门)
  • 微软售后维修点(微软售后维修点江门)
window7下载steam(window7下载一键重装如何恢复网络)

回答如下:要在Windows7上下载Steam,您可以按照以下步骤操作:1.打开您的浏览器,访问Steam官网(https://store.steampowered.com)。2.点击页面右上角...

系统还原没有还原点怎么办(系统还原点不动怎么办)

如果电脑没有创建还原点,就不能使用系统还原来回到之前的状态。但是,可以尝试使用其他备份工具或软件来恢复数据或重建系统。比如,可以使用第三方备份软件来备份重要文件和数据。如果是系统出现问题,可以尝试重新...

正在准备windows(正在准备windows请勿关机怎么办)

这个情况在使用华为电脑时可能会遇到。一般来说,这是因为电脑正在进行系统更新或者安装软件程序等操作,导致启动时间较长。如果电脑显示“正在准备Windows,请勿关闭电源”,则说明电脑正在进行系统更新。...

有win10安装包怎么装系统(win10安装包安装教程)
有win10安装包怎么装系统(win10安装包安装教程)

如果是原版ISO镜像,可以加载到虚拟光驱直接安装。如果是第三方更改的就需要启动盘。个人建议用U盘启动盘来安装。下载一个u盘启动盘程序(优启通、大白菜……),按照提示把它安装到U盘。启动盘制作完毕以后,启动电脑安快捷键选择U盘启动。进入pe后...

2026-01-14 16:37 liuian

gho怎么变成iso文件(gho改成iso)

要将GHO转换为ISO,您需要使用GHO映像转换器软件。以下是执行此操作的步骤:1.下载和安装GHO映像转换器软件。2.运行转换器软件,并单击“打开”按钮。3.在弹出窗口中,选择要转换的GHO...

office和visio安装顺序(office和visio怎么一起安装)

在某些情况下,安装Visio可能会发生与Office365冲突的问题。这是因为Visio和Office365具有不同的版本,可能会导致安装时出现错误或兼容性问题。为了避免这种冲突,...

小白一键装系统(小白一键系统重装)
  • 小白一键装系统(小白一键系统重装)
  • 小白一键装系统(小白一键系统重装)
  • 小白一键装系统(小白一键系统重装)
  • 小白一键装系统(小白一键系统重装)
电脑中病毒的原因(电脑中病毒正常吗)

电脑中毒的原因有以下几方面:1.网页被挂病毒。2.电脑裸奔,无防病毒软件。3.执行一些不安全的程序。4.U盘等不安全介质。5.电脑漏洞不及时补,被后台种毒。为了电脑不中病毒要注意以下几方面:1.更新系...

手机psd转换成jpg最简单方式

可以使用photoshop工具,方法如下:1、首先打开PS软件,然后选择自己需要的JPG格式的图片,在PS中打开。2、接下来先按快捷键“Ctrl+j”将图片复制出来,防止后面操作对原图片有损...

qq好友回复恢复官网(官方qq好友恢复)
  • qq好友回复恢复官网(官方qq好友恢复)
  • qq好友回复恢复官网(官方qq好友恢复)
  • qq好友回复恢复官网(官方qq好友恢复)
  • qq好友回复恢复官网(官方qq好友恢复)