Jump to content

Embed a scripting language in AutoIt


Valik
 Share

Recommended Posts

This is VERY rough code, but it works enough to be a proof of concept. I am not going to maintain this or update it in anyway. I said this could be done in 50 lines or less of code. Counting actual lines of code below, you will see 52, I could trim it to less than 50, but I think I've proved my point well enough with what's here. The known issues are at the top of the script (A quote issue). To start a language block, use:

LANGUAGE-START <TAB> FILEXT <TAB> <PATH TO INTERPRETER>

and to end a block, use:

LANGUAGE-END

Be sure the example is properly TAB delimited if you copy it.

Now, the script itself (Compile this as Parser.exe)

; Known issues:
;    - Quotes: having mixed quotes in the guest language will break the output script because
;    AutoIt also requires the quotes around the string.  This could be fixed by replacing single
;    quotes with double quotes.

Global $InSection = 0
Global $lang = "", $path = "", $tmpFile = @ScriptDir & "\temp.script." & Int(Random(100, 1000)) & "."

Opt("MustDeclareVars", 1)
Main()

Func Main()
    If $CmdLine[0] < 1 Then
        MsgBox(4096, "Error", "Specify a file on the command line")
        Exit(1)
    EndIf
    Local $in = FileOpen($CmdLine[1], 0)
    Local $out = FileOpen($CmdLine[1] & ".new.au3", 2)
    If $in = -1 Or $out = -1 Then
        MsgBox(4096, "Error", "Unable to open a file for reading or writing.")
        Exit(2)
    EndIf
    While 1
        Local $line = FileReadLine($in)
        If @error Then ExitLoop
        Parser($line)
        FileWriteLine($out, $line)
    Wend
    FileClose($in)
    FileClose($out)
EndFunc   ; Main()

Func Parser(ByRef $line)
    Local $start = "#LANGUAGE-START", $end = "#LANGUAGE-END"
    If StringLeft($line, 1) = "#" Then
        If StringLeft($line, StringLen($start)) = $start Then
            ParserSplit($line)
            If @error Then
                MsgBox(4096, "Error", "Error, incorrect syntax, use: " & @CRLF & _
                    "#LANGUAGE-START EXT PATH\TO\INTERPRETER")
                Return SetError(1)
            EndIf
            $InSection = 1
            $tmpFile = $tmpFile & $lang
            $line = 'Local $hTempFile = FileOpen("' & $tmpFile & '", 2)'
        ElseIf StringLeft($line, StringLen($end)) = $end Then
            $InSection = 0
            $line = 'FileClose($hTempFile)' & @CRLF & "RunWait('" & $path & ' "' & $tmpFile & '"'')' & @CRLF & _
                'FileDelete("' & $tmpFile & '")'
        EndIf
    Else
        If $InSection Then $line = "FileWriteLine($hTempFile, '" & $line & "')"
    EndIf
EndFunc

Func ParserSplit($line)
    Dim $a = StringSplit($line, @Tab)
    If @error Or $a[0] < 3 Then Return SetError(1)
    $lang = $a[2]
    $path = '"' & $a[3] & '"'
EndFunc

This is the test script I used to test with:

#LANGUAGE-START VBS C:\Windows\System32\wscript.exe
Dim text 
text = "Hi from VBScript"
msgbox text
#LANGUAGE-END

MsgBox(4096, "", "Hi from AutoIt")

Run it like this:

Parser.exe "Parser Test.au3"

Where "Parser Test.au3" is the path to the file you wish to convert. It will create a new file in the same directory with all the FileWriteLine() stuff.

When running the new file, if everything goes correct, you will get 2 message boxes. One from within VBScript (first) and one from AutoIt (second).

What you do with this code is up to you. You can embed the code in something which forwards the newly created file along to AutoIt3.exe, Aut2Exe.exe or whever. This is a proof of concept of how to embed a language and generate a properly formatted Au3 file from that, nothing more.

Link to comment
Share on other sites

If people really want this (I've seen some ppl request it) shouldn't it be put in as an include or something?

I've wondered why more things don't get put in as includes. Maybe I don't understand what the includes should be used for - technically I guess you could make just about any function an include.

On a related topic: I keep thinking that it would be great to have a central repository of useful scripts and scraps. Don't suggest searching this forum. You know that's not what I mean. :ph34r: Is there any hopes of a grassroots-type effort to cobbled together a list of all fucntioning (I was going to say useful, but then we'd get into semantics) scripts and scraps?

Just my 2 cents.

(Incidentally why isn't useful usefull? You'd think that if something were full of use it would be usefull. You Brits probably spell it properly don't ya. :( )

Raoul S. Duke: Few people understand the psychology of dealing with a highway traffic cop. Your normal speeder will panic and immediately pull over to the side. This is wrong. It arouses contempt in the cop-heart. Make the bastard chase you. He will follow.
Link to comment
Share on other sites

I'm going to have fun with this new toy - thanks Valik!

Meantime ..

(Incidentally why isn't useful usefull?  You'd think that if something were full of use it would be usefull.  You Brits probably spell it properly don't ya. :( )

.. nope, in fact the correct ( :ph34r: ) spelling is also "useful" ... but that's cos it's a cousin to "beatiful" and "harmful" and "awful" .. etc :lol:
Link to comment
Share on other sites

Telling what exactly isn't working about it would be helpful. There's nothing incorrect about your syntax provided:

  • Parser.exe exists.
  • Parser Test.au3 exists in the same directory as Parser.exe.
  • The script with the Run() statement exists in the same directory as Parser.exe and Parser Test.au3.
There is no need to call @ComSpec, however. Parser.exe does not print anything to the console and it's a valid Win32 application. It should be called directly (Although this is not related to the problem, it is unnecessary).
Link to comment
Share on other sites

How would I do it with out @ComSpec ?

This is the error ---------------------------

AutoIt Error

---------------------------

Line 1 (File "E:\Programs\AutoIt3\Examples\july11\what.au3"):

Run(@ComSpec & " /k Parser.exe "Parser Test.au3")

Run(@ComSpec & " /k Parser.exe "Parser Test.au3^ ERROR

Error: String missing closing quote.

---------------------------

OK

--------------------------

-get this error when I remove one of the "

---------------------------

Error

---------------------------

Unable to open a file for reading or writing.

---------------------------

OK

---------------------------

All in the same folder so should work ? Edited by bobheart
Link to comment
Share on other sites

Very strange I did just like you have it and it gave me that error about no file to edit or something like that then it made this file ? Parser Test.au3.new.au3

And didn't say Hi from VBScript .maybe my path is not the same as yours all have to look .

C:\Windows\System32\wscript.exe <--- yours

C:\Windows\System32\wscript.exe <--- mine is the same .

Edited by bobheart
Link to comment
Share on other sites

First off, trust me that I'm very, very thankful that you took time to create a parser for others. Your contributions are always noteworthy and appreciated by users like myself.

Forgive my ignorance, however, I would like to clarify something. The purpose of your code is:

. For even a newbie to AutoIt (for example) to know how to modify your code and place it in their script.

. Use the code to take a file that contains vbscript code (for example) and save it as an .au3

. The code will convert the .vbscript into a format that AutoIt can read via inserting filewrite commands in the appropriate locations.

. Run the temp file and Delete the temp file

This would, in your opinion, be more advantageous and somehow easier for newbie users, part time programmers, and even those experience people trying to save time and be productive than:

. Having the "built in" ability to "cut and paste" different syntax/scripts via AutoIt commands like (external script) ExtScript_Start, ExtScript_End, and a modified run command? Or how about a modified FileWrite command that can do numerous lines and ignore syntax? I also asked about how difficult the modifications would be, since they may be simple for a high level programmer, by the way.

. Running the external whatever.vbs or .js script via RunWait('cscript.exe "c:\long file\name\script.vbs"') or wscript?

Another point would be for such users to be able to use the script to create the multi-line files, scripts, bat, etc... with complex punctuation and syntax while the script is executing and from a single compiled exe.

I'm just amazed by the resistance to make a HUGE enhancement of AutoIt's functionality with something built-in or at least a bit more polished, in regards to windows scripting support. Nevertheless, I'm still thankful.

Edited by autoitNOW
An ADVOCATE for AutoIT
Link to comment
Share on other sites

It doesn't really matter. If you need VBS or other language support so bad, why not use seperate files and call them from AutoIt? It still involves temp files, so that's not a lot different. There are projects that use several languages to complete the task, but they almost always have seperate files that call each other to get the work done.

It does say something that AutoIt can be programmed to be smart enough to parse out code written in a seperate language. However, why not just write the code in a seperate file, and call that language's own parser from AutoIt?

[font="Optima"]"Standing in the rain, twisted and insane, we are holding onto nothing.Feeling every breath, holding no regrets, we're still looking out for something."[/font]Note: my projects are off-line until I can spend more time to make them compatable with syntax changes.

Link to comment
Share on other sites

I'm just amazed by the resistance to make a HUGE enhancement of AutoIt's functionality with something built-in or at least a bit more polished, in regards to windows scripting support. Nevertheless, I'm still thankful.

I'm just amazed that I give you a working product (Admittedly rough, but working) and you're still not satisfied. If you want it polished, then polish it. It's proof-of-concept code, only. The whole point was to demonstrate that it was a trivial matter to enhance AutoIt's syntax via a script in 50 lines or less. You have 80% of what you need to make something with "polish".

It's not even necessary you know how Parser() and ParserSplit() work; treat them as a black box and pass them what they want and they will give you what you want in return. If you're worth half of anything as a scripter, you can put a proxy between AutoIt3.exe/Aut2Exe.exe which looks similar to the above so that when you compile or run, the real AutoIt stuff gets the expanded script with all the FileWriteLines(). You'll never even see them if you properly delete the temporary file after use. None of my scripts ever reach AutoIt without going through a proxy which checks for a few "pre-processor" directives. Other than a few funny keywords in my sources, you'd never have a clue AutoIt3.exe wasn't the first thing called when I choose Run Script.

If you want something done, do it. Stop telling us what you want done, just do it, and if you think other's truly do want it, then make it user-friendly with some way to install/uninstall so "newbies" can easily get it to work. I'm not going to write it for you. Ask any of the regulars here, this is probably the most script I've ever posted for anybody unless I wrote something because I wanted it and was nice enough to post it.

Link to comment
Share on other sites

Valik, I applaud your efforts and contributions, but I did not make a personal request for a parser. This was a solution that you came up to keep AutoIt "pure" and avoid any "built in" abilites of AutoIt to call other script languages, as is being done by numerous other automation/macro recorder tools.

I was talking about Autoit having the built in ability to "call" other script languages from, a "single script that is compiled into an exe", via writing temp files and running those temp files using cscript, etc... while making the process easy and efficient for most AutoIt users.

Please do understand, that I'm not telling or forcing anyone to do anything, but just making suggestions and debating the merits of an idea. I'm not a programmer by trade, so I'm making suggestions based on how AutoIt could possibly be more useful or efficient for many users that use AutoIt to do some complex computer tasks with limited programming skill. Autobuilder, is an example of such a tool.

Nevertheless, don't get the impression that I'm not thankful for your efforts because I am, but this is still a very different path from what I was suggesting. Again, I don't see these things as one versus/minus the other, but a + b= something better and giving users more options.

Edited by autoitNOW
An ADVOCATE for AutoIT
Link to comment
Share on other sites

This was a solution that you came up to keep AutoIt "pure" and avoid any "built in" abilites of AutoIt to call other script languages, as is being done by numerous other automation/macro recorder tools.

I was talking about Autoit having the built in ability to "call" other script languages from, a "single script that is compiled into an exe",  via writing temp files and running those temp files using cscript, etc... while making the process easy and efficient for most AutoIt users.

The problem is that you need a compiler to translate the ASCII code into a binary executable file the computer can run. It works for any machine that has access to the proper parser, but it won't if you don't have that program. For example, if I choose to imbed some C code into my AutoIt script, it will work fine for me since I have Dev-C++ installed at home. But if I send it to a friend, they probably would not be able to run it.

Instead, a much better solution is to write a seperate file in C, compile it with my compiler, and FileInclude it. That way you don't need to run the source through any parser. You can then use little extensions to your AutoIt code when another language is more appropriate to a specific task.

[font="Optima"]"Standing in the rain, twisted and insane, we are holding onto nothing.Feeling every breath, holding no regrets, we're still looking out for something."[/font]Note: my projects are off-line until I can spend more time to make them compatable with syntax changes.

Link to comment
Share on other sites

The problem is that you need a compiler to translate the ASCII code into a binary executable file the computer can run.  It works for any machine that has access to the proper parser, but it won't if you don't have that program.  For example, if I choose to imbed some C code into my AutoIt script, it will work fine for me since I have Dev-C++ installed at home.  But if I send it to a friend, they probably would not be able to run it.

Instead, a much better solution is to write a seperate file in C, compile it with my compiler, and FileInclude it.  That way you don't need to run the source through any parser.  You can then use little extensions to your AutoIt code when another language is more appropriate to a specific task.

Cscript and wscript are already on newer versions of windows (2000, XP, and up). I'm talking about having autoit copying lines between Extscript_start and Extscript_end (for example), ignoring the different syntax while doing so, and then copying that to a temp file.

If anything I want AutoIt to ignore the syntax of everything between start and end. This is being done right now by using the below commands....

#comments-start

...

...

#comments-end

..in AutoIt. The difference would be that AutoIt would be able to copy whatever is between start and end, to send it to a temp file.

In this method, AutoIt does not compile any code. It also has the advantage of making it easy to to copy and paste, add other script languages without dealing with most FileWrite and syntax problems, not having to restructure/re-do the script via send key commands, or having to use another program to convert the script.

Part 1

Extscript_start ("name", "options")

Visual basic script code

Extscript_end

Part 2

Copy Visual basic script or Java script code to temp .vbs or .js file.

Part 3

Run temp .vbs or .js file with cscript or wscript (which usually exist on Windows computers already). Perhaps Part 2 and Part 3 can be done with...

ExtScript_Run ("cscript", "name", "various options") or whatever.

The concept is more in terms of extending FileWrite and # comments ability, but it is called something else to connect it to using an AutoIt script to call other script languages, and that is what it seems Macro Scheduler and others are doing. This method could also be used to call multiple scripting languages from the same user created AutoIt script as well and provided the computer was configured to do so. The AutoIt script does most of the work and they simply "call" bits of other script languages to do something that AutoIt can't, but the primary interface and focus is using AutoIt.

Edited by autoitNOW
An ADVOCATE for AutoIT
Link to comment
Share on other sites

Another way of achieving this without using a separate parser exe would be to extend the CompileAU3 script to output the external language block to a file and then replace that block with a fileinclude and runwait before compiling. Which is of course the same as Valik's version, except that the external language script is 'FileIncluded' with the AU3 script.

:iamstupid: Sorry....just realised you can only fileinclude fixed path files.

Edited by pacman
Link to comment
Share on other sites

My whole point was that the machine does compile all code before it runs it. It has to since it's a computer. You can't just "run" VBS source. Even when you double click on a .vbs file, it still has to compile it first. I don't don't see why you would ever want to write code for a different language in a file that doesn't have the extension of that language. No editor is going to syntax highlight your code, and your writing it to a 2nd tempfile anyway. Isn't it eaisier to write the code in a seperate file, and FileInclude it with your script? Even if it is a VBS file that you are including and running, what do you gain from putting it all in one file?

Maybe I'm just missing the ultimate purpose, but when I write multi-language projects, they always are in seperate files that call each other and not in some hybrid single file. With all the different syntax from various languages, you can't have them all display properly in a single editor session, so you really need multipile files if you want to do any serious programming anyway.

[font="Optima"]"Standing in the rain, twisted and insane, we are holding onto nothing.Feeling every breath, holding no regrets, we're still looking out for something."[/font]Note: my projects are off-line until I can spend more time to make them compatable with syntax changes.

Link to comment
Share on other sites

I modded Valik's code to use FileInstall to include the external language block with the main AU3 script.

; Known issues:
;    - Quotes: having mixed quotes in the guest language will break the output script because
;    AutoIt also requires the quotes around the string.  This could be fixed by replacing single
;    quotes with double quotes.

Global $InSection = 0
Global $lang = "", $path = "", $tmpFile = @ScriptDir & "\temp.script." & Int(Random(100, 1000)) & "."

Opt("MustDeclareVars", 1)
Main()

Func Main()
   If $CmdLine[0] < 1 Then
       MsgBox(4096, "Error", "Specify a file on the command line")
       Exit(1)
   EndIf
   Local $in = FileOpen($CmdLine[1], 0)
   Local $out = FileOpen($CmdLine[1] & ".new.au3", 2)
   If $in = -1 Or $out = -1 Then
       MsgBox(4096, "Error", "Unable to open a file for reading or writing.")
       Exit(2)
   EndIf
   While 1
       Local $line = FileReadLine($in)
       If @error Then ExitLoop
       If Parser($line) Then FileWriteLine($out, $line)
   Wend
   FileClose($in)
   FileClose($out)
EndFunc  ; Main()

Func Parser(ByRef $line)
   Local $start = "#LANGUAGE-START", $end = "#LANGUAGE-END"
   Local $extFile
   If StringLeft($line, 1) = "#" Then
       If StringLeft($line, StringLen($start)) = $start Then
           ParserSplit($line)
           If @error Then
               MsgBox(4096, "Error", "Error, incorrect syntax, use: " & @CRLF & _
                   "#LANGUAGE-START,EXT,PATH\TO\INTERPRETER")
               Return SetError(1)
           EndIf
           $InSection = 1
           $tmpFile = $tmpFile & $lang
           Return 0
       ElseIf StringLeft($line, StringLen($end)) = $end Then
           $InSection = 0
           $extFile = "\temp.script." & Int(Random(100, 1000)) & "." & $lang
           $line = 'FileInstall("' & $tmpFile & '", @ScriptDir & "' & $extFile & '")' & @CRLF
           $line = $line & 'RunWait(' & $path
           $line = $line & ' & " """ & @ScriptDir & "' & $extFile & '""")' & @CRLF
           $line = $line & 'FileDelete(@ScriptDir & "' & $extFile & '")'
       EndIf
   Else
       If $InSection Then
          FileWriteLine($tmpFile, $line)
          Return 0
       EndIf
   EndIf
   Return 1 
EndFunc

Func ParserSplit($line)
   Dim $a = StringSplit($line, ",")
   If @error Or $a[0] < 3 Then Return SetError(1)
   $lang = $a[2]
   $path = '"' & $a[3] & '"'
EndFunc
Link to comment
Share on other sites

My whole point was that the machine does compile all code before it runs it.  It has to since it's a computer.  You can't just "run" VBS source.  Even when you double click on a .vbs file, it still has to compile it first.  I don't don't see why you would ever want to write code for a different language in a file that doesn't have the extension of that language.  No editor is going to syntax highlight your code, and your writing it to a 2nd tempfile anyway.  Isn't it eaisier to write the code in a seperate file, and FileInclude it with your script?  Even if it is a VBS file that you are including and running, what do you gain from putting it all in one file?

Maybe I'm just missing the ultimate purpose, but when I write multi-language projects, they always are in seperate files that call each other and not in some hybrid single file.  With all the different syntax from various languages, you can't have them all display properly in a single editor session, so you really need multipile files if you want to do any serious programming anyway.

Pekster, SciTe can be used to edit the VBscript and Jscript separately. AutoIt commands like #comments-start or proposed commands like ExtScript_start, would mean that AutoIt would ignore the syntax when copied into the script. When the script is compiled into a single exe, it would then run the various scripting languages. AutoIt would be the main scripting language and the other scripting languages would be used to perform specific functions that AutoIt can't, but for a specific project.

Many people that use scripts like VBScript or Jscript want the ability to protect their code and have more portability in terms of needing less files. You can "encode" your scripts, but that is not as good as having it as part of your Autoit compiled script turned exe and does not address the problem of needing less files. The compiled AutoIt script would contain the VBScript/JScript code in a single exe, send the code to a temp file with the .vbs or .js extension, and then run the cscript/wscript command to execute it. Another side advantage of this same methodology would also be used to make it easier to send large amount of text to text files.

Pacman, I agree with you. Check the below...

FileInstall ("d:\test.vbs", "c:\test.vbs")

RunWait('cscript.exe "c:\test.vbs"')

FileDelete("c:\test.vbs")

When compiled the test.vbs will be included in the .exe As a newbie, I overlooked this, because as a script it just does copy.

Or your welcomed addition to Valik's very good parser method is a way of adding more .vbs or .js scripting functionality.

The only problem with FileInstall is the fixed path files and maybe somebody would want to add an option or something or make changes... Another thing is that because of the way the files are named and lack of specific examples of this type of situation in the help means that it will usually be overlooked.

I'm also saying, why not be more forward, supportive, and add various options in AutoIt to incorporate other script languages. Allowing users that want to use "bits of code" from other scripting languages to do something that AutoIt can't, but still use AutoIt as their MAIN interface. This type of support would just make AutoIt more popular and useful. Users needing that type of support would not have to "beat their head against the wall", because it would be easy for everyone to say, "Hey do X and you got what you need."

Edited by autoitNOW
An ADVOCATE for AutoIT
Link to comment
Share on other sites

@ aoutoitNOW:

You seem to have some well thought out ideas. I believe the AU3 source code is available for scrutiny and enhancements, and I have found the AU3 developers to be receptive to improvements. Have you considered prototyping your solution for them to feedback on? I am sure that Jon will be happy to guide you, based on the collaborative spirit of threads in the v3 Developers forum, and on your demonstrated enthusiasm to improve AutoIt.

Hope this helps :ph34r:

Link to comment
Share on other sites

AutoIt would be the main scripting language and the other scripting languages would be used to perform specific functions that AutoIt can't, but for a specific project.

I do that already with some sort routines I've written using a console C application. Your idea offers me nothing I haven't already been doing.

You can "encode" your scripts, but that is not as good as having it as part of your Autoit compiled script turned exe and does not address the problem of needing less files.

Your method uses just as many "extra files" as mine does. You need to dump your commands between the directives to a tempfile (vbs, .c, etc) and then compile them. This also only works as long as each user can compile the respective sources that you export to the tempfile. When I write routines using C, not all of my target users have Dev-C++ installed excatally where I have it, and therefore I can't expect to be able to compile it on the fly.

The compiled AutoIt script would contain the VBScript/JScript code in a single exe, send the code to a temp file with the .vbs or .js extension, and then run the cscript/wscript command to execute it.  Another side advantage of this same methodology would also be used to make it easier to send large amount of text to text files.

Same thing with my method. The compiled scripts contains whatever binary you want to use, dumps it to some file (either in the script's dir, or the temp dir) and execute it. What if the user you want to run your app doesn't have the scripting language you're using? How do they run your add-in language if they can't compile it?

The only problem with FileInstall is the fixed path files and maybe somebody would want to add an option or something or make changes...

Take a look at my example titled "On the fly file install" from my project page. Here I demonstrate how to FileInstall some text, read it, and then delete it before a user even sees it. Yet I managed to include this in my sources just fine. You can edit this all you like, point the source to your hardcoded path, and recompile it. I fail to see how you can't make changes if the files you are including have their respective sources included...

Another thing is that because of the way the files are named and lack of specific examples of this type of situation in the help means that it will usually be overlooked.

Okay, this makes no sense to me. "the way the files are named" ??? Can't you change file names so they represent what they are?

Allowing users that want to use "bits of code" from other scripting languages to do something that AutoIt can't, but still use AutoIt as their MAIN interface.  This type of support would just make AutoIt more popular and useful.

How can you not do that already? VSB is one of the few languages that doesn't require an external compiler because it is already built into the OS. What about perl or C or python, etc? How do you expect to be able to run a .py file if you don't have the interperter for it? Doesn't it seem a lot more practical to compile it on your end, inlcude that in your binary release of the script, and then include the .py source in your source release of your code so that others can edit it?

My whole point is that this method only works as long as you can just "run" the source. You can't do that unless the target computer has a compiler for it. And even if you know all your users have it, how do you know it'll be installed to the same directory to call the compiler? You don't know that, so your method is not as "all allowing" as including a binary would be. Any user can run a compiled binary, but only a developer in that language would be likely to run your sources.

Typo fix

Edited by pekster

[font="Optima"]"Standing in the rain, twisted and insane, we are holding onto nothing.Feeling every breath, holding no regrets, we're still looking out for something."[/font]Note: my projects are off-line until I can spend more time to make them compatable with syntax changes.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...