 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
arbe
Joined: 12 Apr 2005 Posts: 30
|
Posted: Tue Aug 29, 2006 8:07 pm Post subject: AHK preprocessor |
|
|
Hi AHK-community!
We recently had a discussion about the use of preprocessing an AHK file (see http://www.autohotkey.com/forum/topic4573.html).
I built a preprocessor that supports the following code:
| Code: | #DEFINE test
#IFDEF test
msgbox This code is executed.
#ELSE
msgbox This code is commented out.
#ENDIF
#IFNDEF test
msgbox This code is commented out.
#ENDIF
|
The major use-case it supports is compiler switches for a published and a private version of your script. But you can think of many other scenarios like debugging, logging, personalization, etc.
It does also handle #INCLUDE, but the restriction is that it only supports absolute pathes.
Of course, in a scripting language like AHK one can do the same with dynamic code. But I dislike turning off hotkeys via the hotkey command etc. I think my preprocessor is a much cleaner solution.
How does it work? Compile the script below and drag&drop your script enhanced with the commands on the executable. The preprocessed files are located in the same directory as the source files, but carry the double extension .PREPROCESSED.ahk instead of .ahk only. By commenting out undefined sections instead of deleting them, the line numbers stay the same as in the source files. Remember that your .ahk source files are not of valid AHK-syntax anymore (due to #DEFINE commands being unknown to AHK). You can only run and compile the preprocessed versions, but you should make your changes only to the original source files (since preprocessed files are of temporary nature and will be overwritten in every preprocessing step).
This is the code of the preprocessor:
| Code: | ; Autohotkey preprocessor by arbe
; Syntax: preprocessor.exe [-run] [-deleteLines | -clearLines] scriptPath
#NoEnv
; Check syntax and store variables passed on command line
terminateDueToBadSyntax() {
msgbox Syntax: preprocessor.exe [-run] [-deleteLines | -clearLines] scriptPath
exitapp
}
if 0 = 0
terminateDueToBadSyntax()
Loop %0%
{
param := %A_Index%
if param = -run
followupAction = run
else if param = -deleteLines ; delete not defined lines instead of out-commenting them (attention: AHK debug messages will not show the same line numbers as in the source files anymore).
deleteLines := true
else if param = -clearLines ; does not delete but clear (blank out) undefined lines
clearLines := true
else
scriptPath := param
}
if scriptPath=
terminateDueToBadSyntax()
IfNotExist %scriptPath%
terminateDueToBadSyntax()
; recursive main preprocessing function call. Returns the output path of preprocessed script.
preprocess(inPath)
{
global defines
global deleteLines
global clearLines
StringTrimRight outPath, inPath, 4
outPath = %outPath%.PREPROCESSED.ahk
FileDelete %outPath%
Loop read, %inPath%, %outPath%
{
; strip of comments for internal representation and trim line:
line := A_LoopReadLine
temp := InStr(line, ";")
if temp > 0
StringLeft line, line, temp-1
line = %line%
; extract commands:
indexAfterCommand := InStr(line, A_Space)
if indexAfterCommand > 0
StringLeft commandName, A_LoopReadLine, indexAfterCommand-1
else
commandName := A_LoopReadLine
StringTrimLeft commandParameter, line, indexAfterCommand
defineObject=|%commandParameter%|
; check commands
lineText=;%A_LoopReadLine% ; default for the following commands is blankout
if commandName = #DEFINE
{
IfNotInString defines, defineObject
defines=%defines%%defineObject%
}
else if commandName = #IFDEF
{
; check for nested if
if modeIf
{
MsgBox Nested IFDEF not supported by preprocessor.`nLine %A_Index% in %inPath%
ExitApp
}
modeIf := true
modeValue := Instr(defines, defineObject)
}
else if commandName = #IFNDEF
{
; check for nested if
if modeIf
{
MsgBox Nested IFNDEF not supported by preprocessor.`nLine %A_Index% in %inPath%
ExitApp
}
modeIf := true
modeValue := !Instr(defines, defineObject)
}
else if commandName = #ELSE
{
; check for bad syntax
if !modeIf
{
MsgBox #ELSE without #IFDEF or #IFNDEF encountered by preprocessor.`nLine %A_Index% in %inPath%
ExitApp
}
modeValue:=!modeValue
}
else if commandName = #ENDIF
{
; check for bad syntax
if !modeIf
{
MsgBox #ENDIF without #IFDEF or #IFNDEF encountered by preprocessor.`nLine %A_Index% in %inPath%
ExitApp
}
modeIf := false
}
else if commandName = #INCLUDE
{
if (modeIf AND !modeValue) ; handle disabled includes via ifdef
lineText=`;%A_LoopReadLine%
else
{
IfExist %commandParameter%
{
temp := preprocess(commandParameter)
lineText=#INCLUDE %temp%
}
else
{
MsgBox Include file %commandParameter% not found. Preprocessor does only support absolute pathes.`nLine %A_Index% in %inPath%
ExitApp
}
}
}
else
{
if (modeIf AND !modeValue)
{
if deleteLines
lineText=#MARKEDFORDELETION
else if clearLines
lineText=
else
lineText=`;%A_LoopReadLine%
}
else
lineText=%A_LoopReadLine%
}
if lineText<>#MARKEDFORDELETION
FileAppend %lineText%`n
}
return outPath
}
; parse files and write output recursively (#input)
temp := preprocess(scriptPath)
; if asked for, run next step
if followupAction=run
Run %temp%
|
Last edited by arbe on Sun Sep 03, 2006 9:50 am; edited 2 times in total |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Wed Aug 30, 2006 1:52 pm Post subject: |
|
|
Very nice script. This should be useful to those craving preprocessor capabilities. It will also be useful to me when the time comes to build in such features.
Thanks. |
|
| Back to top |
|
 |
Rabiator
Joined: 17 Apr 2005 Posts: 265 Location: Sauerland
|
Posted: Wed Aug 30, 2006 8:34 pm Post subject: Re: AHK preprocessor |
|
|
Hey, nice work!
I will use it to write similar - but not identical - scripts for several users, so I only have to control one "master" script.
2 suggestions:
an option to delete the out-commented lines a preprocessor command like #ELSEIFDEF (Kernighan & Ritchie forgot this in C and caused billions of unnecessarily nested and inscrutable preprocessor lines )
| Code: | Now: Golden future:
#IFDEF A #IFDEF A
MsgBox A MsgBox A
#ELSE #ELSEIFDEF B
#IFDEF B MsgBox B
MsgBox B #ELSEIFDEF C
#ELSE MsgBox C
#IFDEF C #ELSEIFDEF D
MsgBox C MsgBox D
#ELSE #ELSE
#IFDEF D MsgBox another letter
MsgBox D #ENDIF
#ELSE
MsgBox another letter
#ENDIF
#ENDIF
#ENDIF
#ENDIF
|
|
|
| Back to top |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6721 Location: France (near Paris)
|
Posted: Thu Aug 31, 2006 9:18 am Post subject: |
|
|
I haven't used it yet, but it looks like well implemented, and its usefulness starts to show...
I like Rabiator suggestions...
I will add another: like many preprocessors, it would be nice to be able to set a define on the command line:
preprocessor.exe [-run] [-strip] [-DFOO ...] scriptPath
I see you process a #INCLUDE command, but it already exists in AutoHotkey, perhaps you should rename it. _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
arbe
Joined: 12 Apr 2005 Posts: 30
|
Posted: Sat Sep 02, 2006 9:20 am Post subject: |
|
|
Chris, Rabiator, and PhiLho,
thanks for your interest!
I liked the suggestion about deleting not defined lines and modified the script. Rabiator, please be aware that AHK's debug messages show line numbers that do not match those in your source files anymore, when you delete those lines. For compiled scripts this should not be a problem. The good thing about this feature is supporting the 'need to know'-principle.
Your suggestion of #ELSEIFDEF is a nice idea. But please be aware that this is a basic version of an AHK preprocessor intended mainly for my personal use. As noted in the script, even nested #IFDEFs are not supported. Are your preprocessing conditions really that complicated that you can not just go for this?
| Code: | #IFDEF A
msgbox A
#ENDIF
#IFDEF B
msgbox B
#ENDIF |
PhiLho, I have decided against command line defines due to the alternative of having a define file that includes your main script at the end. That way, you can have several sets of defines for one script that are easy to edit.
| Code: | #define a
#define b
#include c:\my_master_script.ahk |
Regarding your comment about #INCLUDEs, I think you misunderstood the script a bit. It is necessary to handle the original AHK command. I did not intent to extend any functionality here, since Chris implemented include-preprocessing already. But in order to handle 'distributed scripts' with defines, I need to recursively preprocess all include files. You might just want to give it a try by preprocessing one of your scripts that has includes. |
|
| Back to top |
|
 |
Rabiator
Joined: 17 Apr 2005 Posts: 265 Location: Sauerland
|
Posted: Sat Sep 02, 2006 5:56 pm Post subject: |
|
|
| arbe wrote: | | Rabiator, please be aware that AHK's debug messages show line numbers that do not match those in your source files anymore, when you delete those lines. |
The intention was to hide information among users if you share the generated scripts. The lines have not to be deleted completely, the CR could remain, so the line numbers were consistent.
| Quote: | | ... #ELSEIFDEF ... for my personal use. ... Are your preprocessing conditions really that complicated that you can not just go for this? |
Of course not, but it's very hard without #ELSEIFDEF.
Please don't feel constrained to integrate these suggestions, I'm pleased that you built this functionality as it is.  |
|
| Back to top |
|
 |
arbe
Joined: 12 Apr 2005 Posts: 30
|
Posted: Sun Sep 03, 2006 9:54 am Post subject: |
|
|
| Rabiator wrote: | | The lines have not to be deleted completely, the CR could remain, so the line numbers were consistent. |
Thanks for the hint. You are absolutely right, I added the option -clearLines.
| Rabiator wrote: | Please don't feel constrained to integrate these suggestions, I'm pleased that you built this functionality as it is.  |
I'm glad it's not only useful for me! But since I don't see the necessity for nested IFDEFs or ELSEIFDEFs, I will not implement them in the near future. So please feel free to modify the code yourself, if you like. |
|
| Back to top |
|
 |
Rabiator
Joined: 17 Apr 2005 Posts: 265 Location: Sauerland
|
Posted: Mon Sep 04, 2006 10:44 pm Post subject: |
|
|
| arbe wrote: | | I added the option -clearLines. | Thanks.  |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|