I often had to rewrite the simple AutoIt3 code into PureBasic code and it was time consuming if done manually, so I decided to automate. In the beginning, I made regular expressions and didn't save them as it was a temporary task. But when this happened several times, I decided to write it in the form of a converter. Of course, this is not a full-fledged converter, and even most of the code must be done manually, but at least eliminate routine work.
Code: Select all
EnableExplicit
Global Error_Procedure = 0
Global Text.string
Define Text$, File$, Format, CountP
Structure ReplaceGr
pos.i
ngr.i
group.s
EndStructure
; https://www.purebasic.fr/english/viewtopic.php?p=575871
Procedure RegexReplace2(RgEx, *Result.string, Replace0$, Escaped = 0)
Protected i, CountGr, Pos, Offset = 1
Protected Replace$
Protected NewList item.s()
Protected LenT, *Point
; Static RE2
; Static RE3
Protected RE2
Protected NewList ReplaceGr.ReplaceGr()
CountGr = CountRegularExpressionGroups(RgEx)
; ограничение групп, только обратные ссылки \1 .. \9
If CountGr > 9
CountGr = 9
EndIf
If ExamineRegularExpression(RgEx, *Result\s)
; Поиск Esc-символов в поле замены регвыр
If Escaped
Replace0$ = ReplaceString(Replace0$, "\r", #CR$)
Replace0$ = ReplaceString(Replace0$, "\n", #LF$)
Replace0$ = ReplaceString(Replace0$, "\t", #TAB$)
Replace0$ = ReplaceString(Replace0$, "\f", #FF$)
EndIf
; Поиск ссылок на группы в поле замены регвыр
RE2 = CreateRegularExpression(#PB_Any, "\\\d")
If RE2
If ExamineRegularExpression(RE2, Replace0$)
While NextRegularExpressionMatch(RE2)
If AddElement(ReplaceGr())
ReplaceGr()\pos = RegularExpressionMatchPosition(RE2) ; позиция
ReplaceGr()\ngr = ValD(Right(RegularExpressionMatchString(RE2), 1)) ; номер группы
ReplaceGr()\group = RegularExpressionMatchString(RE2) ; текст группы
EndIf
Wend
EndIf
FreeRegularExpression(RE2) ; убрать строку при Static
EndIf
If Not ListSize(ReplaceGr())
*Result\s = ReplaceRegularExpression(RgEx, *Result\s, Replace0$)
ProcedureReturn
EndIf
; Сортировка по позиции, чтобы делать замены с конца и не нарушались ранее найденные позиции
SortStructuredList(ReplaceGr(), #PB_Sort_Descending, OffsetOf(ReplaceGr\pos), TypeOf(ReplaceGr\pos))
While NextRegularExpressionMatch(RgEx)
Pos = RegularExpressionMatchPosition(RgEx)
Replace$ = Replace0$
ForEach ReplaceGr()
If ReplaceGr()\ngr
Replace$ = ReplaceString(Replace$, ReplaceGr()\group, RegularExpressionGroup(RgEx, ReplaceGr()\ngr), #PB_String_CaseSensitive, ReplaceGr()\pos, 1)
Else
Replace$ = ReplaceString(Replace$, ReplaceGr()\group, RegularExpressionMatchString(RgEx), #PB_String_CaseSensitive, ReplaceGr()\pos, 1) ; обратная ссылка \0
EndIf
Next
; item() = часть строки между началом и первым совпадением или между двумя совпадениями + результат подстановки групп
If AddElement(item())
item() = Mid(*Result\s, Offset, Pos - Offset) + Replace$
EndIf
Offset = Pos + RegularExpressionMatchLength(RgEx)
Wend
If AddElement(item())
item() = Mid(*Result\s, Offset)
EndIf
; Формирования текстового списка
; Debug "Count = " + Str(ListSize(item()))
; Count = ListSize(item())
LenT = 0
ForEach item()
LenT + Len(item()) ; вычисляем длину данных для вмещения частей текста
Next
*Result\s = Space(LenT) ; создаём строку забивая её пробелами
*Point = @*Result\s ; Получаем адрес строки
ForEach item()
CopyMemoryString(item(), @*Point) ; копируем очередной путь в указатель
Next
; Конец => Формирования текстового списка
FreeList(item()) ; удаляем список, хотя в функции наверно это не требуется
EndIf
EndProcedure
; FlagsRE
; 16 - поддержка групп - флиг исключён
; 32 - поддержка \n\r\t\f
Procedure RegExpReplace(*s.string, regexp$, replace$, FlagsRE = 0)
Protected Escaped, nRE
Error_Procedure = 0
; If Not Asc(*s\s)
If *s\s = ""
Error_Procedure = 1
ProcedureReturn
EndIf
nRE = CreateRegularExpression(#PB_Any, regexp$, FlagsRE)
If nRE
Escaped = FlagsRE & 32 ; флаг метасимволов \n\r\t\f
; If FlagsRE & 16 Or Escaped
RegexReplace2(nRE, *s, replace$, Escaped)
; Else
; *s\s = ReplaceRegularExpression(nRE, *s\s, replace$)
; EndIf
FreeRegularExpression(nRE)
Else
Error_Procedure = 2
*s\s = RegularExpressionError()
EndIf
EndProcedure
; Открытие файла из ком строки или диалога
CountP = CountProgramParameters()
If CountP
File$ = ProgramParameter(0)
Else
File$ = OpenFileRequester("", GetCurrentDirectory(), "AutoIt3 (*.au3)|*.au3", 0)
EndIf
If Not (Asc(File$) And FileSize(File$) > 0)
End
EndIf
; чтение файла
#File = 0
If ReadFile(#File, File$)
Format = ReadStringFormat(#File)
Text\s = ReadString(#File, Format | #PB_File_IgnoreEOL)
; Text\s = ReadString(#File, #PB_UTF8 | #PB_File_IgnoreEOL)
CloseFile(#File)
EndIf
If Not Asc(Text\s)
End
EndIf
RegExpReplace(@Text, "(\$)(\w+)", "\2\1") ; переменные
RegExpReplace(@Text, "(?mi)^\h*Func\h*(?=\w+\h*\()", "Procedure ") ; процедуры
RegExpReplace(@Text, "(?mi)^\h*EndFunc", "EndProcedure") ;
RegExpReplace(@Text, "\bReturn\b", "ProcedureReturn") ;
RegExpReplace(@Text, "\bLocal\b", "Protected") ;
RegExpReplace(@Text, "\bContinueLoop\b", "Continue") ; ContinueCase(?)
RegExpReplace(@Text, "\bExitLoop\b", "Break") ;
RegExpReplace(@Text, "\bEnum\b", "Enumeration") ;
RegExpReplace(@Text, "\bExit\b", "End") ;
RegExpReplace(@Text, "\[(\d+)\]", "(\1)") ; элементы массива
ReplaceString(Text\s, "&", "+", #PB_String_InPlace) ; конкатенакция строк
ReplaceString(Text\s, "'", Chr(34), #PB_String_InPlace) ; апостроф на кавычки
RegExpReplace(@Text, "([+/*-])=", "\1") ; арифметической действие без приравнивания
RegExpReplace(@Text, "\bi\$", "i") ; счётчик в циклах всегда число
RegExpReplace(@Text, "(?mi)(^\h*)Do\b", "\1Repeat") ; циклы
RegExpReplace(@Text, "(?mi)(^\h*If .+?) Then\r?$", "\1") ; условие в несколько строк, убирается "Then"
RegExpReplace(@Text, "(?mi)^(\h*)(If .+?) Then ([^\r\n;]+?)\r?$", "\1\2\r\n\t\1\3\r\n\1EndIf", 32) ; условие в одну строку преобразуется в многострочное
RegExpReplace(@Text, "(?mi)^\h*Global\h+Const\h+(\w+?)\$\h*=\h*0x([\dA-F]+)\r?$", "#\1 = $\2") ; константы 16-ричные
RegExpReplace(@Text, "(?mi)^\h*Global\h+Const\h+(\w+?)\$\h*=\h*([\dA-F]+)\r?$", "#\1 = \2") ; константы 10-ричные
RegExpReplace(@Text, "(?mi)^(\h*)Switch\b", "\1Select")
RegExpReplace(@Text, "(?mi)^(\h*)EndSwitch\b", "\1EndSelect")
RegExpReplace(@Text, "(?mi)^(\h*)Case Else\b", "\1Default")
RegExpReplace(@Text, "(?mi)\bTrue\b", "#True")
RegExpReplace(@Text, "(?mi)\bFalse\b", "#False")
RegExpReplace(@Text, "\b([A-Z][A-Z_\d]*?)\$(?=[^\w])", "#\1") ; неявное правило - переменные в верхнем регистре являются константами.
; если переменная приравнивается к числу то удаляем $ в имени переменной,
; но проблема, что надо все переменые в заданном пространстве переименовывать
; так что это ненадёжно
; RegExpReplace(@Text, "(\w+)\$(?=\h*=\h*-?\d)", "\1")
Text\s = ReplaceString(Text\s, "@error", "g_Error_Procedure") ; глобальная. В начале функции задаётся в 0. Флаг ошибки.
Text\s = ReplaceString(Text\s, "@extended", "g_Extended_Procedure") ; глобальная. В начале функции задаётся в 0. Флаг дополнительного значения.
Text\s = ReplaceString(Text\s, "#include-once", "") ; инклуды 1 раз включает
Text\s = ReplaceString(Text\s, "#include ", "XIncludeFile ") ; инклуды
; Функции
RegExpReplace(@Text, "\bMsgBox\h*\(([^;,]+?),\h*([^;,]+?),\h*([^;,]+?)\h*\)", "MessageRequester(\2, \3, \1)")
RegExpReplace(@Text, "\bInputBox(?=\h*\()", "InputRequester")
RegExpReplace(@Text, "\bSleep(?=\h*\()", "Delay")
RegExpReplace(@Text, "\bStringInStr(?=\h*\()", "FindString")
RegExpReplace(@Text, "\bStringUpper(?=\h*\()", "UCase")
RegExpReplace(@Text, "\bStringLower(?=\h*\()", "LCase")
RegExpReplace(@Text, "\bStringLen(?=\h*\()", "Len")
RegExpReplace(@Text, "\bStringMid(?=\h*\()", "Mid")
RegExpReplace(@Text, "\bNumber(?=\h*\()", "Val")
RegExpReplace(@Text, "\bString(?=\h*\()", "Str")
RegExpReplace(@Text, "\b(Run|ShellExecute)(?=\h*\()", "RunProgram")
RegExpReplace(@Text, "\bFileCopy(?=\h*\()", "CopyFile")
RegExpReplace(@Text, "\bFileDelete(?=\h*\()", "DeleteFile")
RegExpReplace(@Text, "\bFileExists(?=\h*\()", "FileSize")
RegExpReplace(@Text, "\bFileGetSize(?=\h*\()", "FileSize")
RegExpReplace(@Text, "\bFileSetAttrib(?=\h*\()", "SetFileAttributes")
RegExpReplace(@Text, "\bFileGetAttrib(?=\h*\()", "GetFileAttributes")
RegExpReplace(@Text, "\bDirCopy(?=\h*\()", "CopyDirectory")
RegExpReplace(@Text, "\bDirCreate(?=\h*\()", "CreateDirectory")
RegExpReplace(@Text, "\bDirRemove(?=\h*\()", "DeleteDirectory")
RegExpReplace(@Text, "\bFileSetTime(?=\h*\()", "SetFileDate")
RegExpReplace(@Text, "\bFileChangeDir(?=\h*\()", "SetCurrentDirectory")
RegExpReplace(@Text, "\bStringReplace(?=\h*\()", "ReplaceString")
RegExpReplace(@Text, "\bFileMove(?=\h*\()", "RenameFile")
RegExpReplace(@Text, "\bStringReverse(?=\h*\()", "ReverseString")
RegExpReplace(@Text, "\bTimerInit(?=\h*\()", "ElapsedMilliseconds")
RegExpReplace(@Text, "\bClipGet(?=\h*\()", "GetClipboardText")
RegExpReplace(@Text, "\bClipPut(?=\h*\()", "SetClipboardText")
RegExpReplace(@Text, "\bMemGetStats(?=\h*\()", "MemoryStatus")
; макросы
RegExpReplace(@Text, "@WorkingDir", "GetCurrentDirectory()")
RegExpReplace(@Text, "@TempDir", "GetTemporaryDirectory()")
RegExpReplace(@Text, "@DesktopWidth", "DesktopWidth(0)")
RegExpReplace(@Text, "@DesktopHeight", "DesktopHeight(0)")
RegExpReplace(@Text, "@ScriptDir", "GetPathPart(ProgramFilename())")
RegExpReplace(@Text, "@TAB", "#TAB$")
RegExpReplace(@Text, "@CRLF", "#CRLF$")
RegExpReplace(@Text, "@LF", "#LF$")
RegExpReplace(@Text, "@CR", "#CR$")
RegExpReplace(@Text, "@OSVersion", "OSVersion()")
RegExpReplace(@Text, "@UserName", "UserName()")
; RegExpReplace(@Text, "1111", "2222") ;
; RegExpReplace(@Text, "1111", "2222") ;
; Начало DllCall
Procedure Split(String.s, Array StringArray.s(1), Separator.s = " ")
Protected S.String, *S.Integer = @S
Protected.i asize, i, p, slen
asize = CountString(String, Separator)
slen = Len(Separator)
ReDim StringArray(asize)
*S\i = @String
While i < asize
p = FindString(S\s, Separator)
StringArray(i) = PeekS(*S\i, p - 1)
*S\i + (p + slen - 1) << #PB_Compiler_Unicode
i + 1
Wend
StringArray(i) = S\s
*S\i = 0
EndProcedure
Procedure.s ParseParam(string$)
Protected Dim Param.s(1)
Protected res$, i
Split(string$, Param(), ",")
For i = 1 To ArraySize(Param()) Step 2
res$ + Param(i) + ","
Next
res$ = LTrim(res$)
ProcedureReturn RTrim(res$, ",")
EndProcedure
Procedure FindDllCall(*s.string)
Protected nRE, Groups, FuncName$, Param$
nRE = CreateRegularExpression(#PB_Any, ~"(?i)DllCall\\h*\\([^,]+?,[^,]+?,\\h*\"(\\w+?)\"\\h*,(.+?)\\)", 0)
If nRE
If ExamineRegularExpression(nRE, *s\s)
While NextRegularExpressionMatch(nRE)
FuncName$ = RegularExpressionGroup(nRE, 1) + "_(" + ParseParam(RegularExpressionGroup(nRE, 2)) + ")"
; Debug FuncName$
*s\s = ReplaceString(*s\s, RegularExpressionMatchString(nRE), FuncName$)
Wend
EndIf
FreeRegularExpression(nRE)
EndIf
EndProcedure
FindDllCall(@Text)
; Конец DllCall
Text\s = "EnableExplicit" + #CRLF$ + #CRLF$ + Text\s
#File = 0
If CreateFile(#File, File$ + ".pb")
WriteStringFormat(#File, #PB_UTF8)
WriteString(#File, Text\s, #PB_UTF8)
CloseFile(#File)
EndIf