Jump to content
dekugelschieber

ASL - Arma Scripting Language (Compiler)

Recommended Posts

Hello there,

 

I'm proud to present my first contribution to the Arma 3 Community! As a software developer, I was really excited to play around using SQF. But soon I realized how annoying the syntax can be. Especially for new scripters. So I decided, after writing some scripts to make life easier, like loadout scripts and automatic zeus assignment, to create my own little scripting language which can be compiled to SQF. ASL stands for Arma Scripting Language, is C-like and cleaner than SQF. It adds some comfort to scripting and I intend to add more in the future.

 

Here is an example for an ASL script (for more details visit the GitHub page, link below):

#define X 1

// declare a function (allowing optional parameters)
func myFunc(_a = 0, _b = 0) {
    if _a < _b {
        return "a is less than b";
    } else {
        return "b is less than a";
    }
}

// declare variables
var _x = X;
var _y = 2;
var _someArray = [1, 2, 3];

// assign/access a variable
_x = 3;
_z = _someArray[2]; // = 3

while true {
    // call a build in function
    hint(myFunc(_x, _y));
    hint(myFunc()); // with predefinded parameters
}

ASL is available on GitHub and can be downloaded for Windows and Linux (in fact I developed it on Linux using the experimental build). You can find more details and syntax specification over there.

Feedback is welcome. If you encounter any bugs or would like to participate, let me now on GitHub by creating an Issue or a Pull Request. You can also leave me a post here.

 

Examples

 

If you're intersted in seeing more code, I wrote some of my old scripts in ASL: https://github.com/DeKugelschieber/ArmA3-scripts/tree/master/src/sts_mission_template.Altis/scripts/dklib

To build it, download ASL and the GUI, select the scripts as input and the mission folder itself (which contains the script folder) as output.

 

GUI

 

There is a graphical user interface which you can use instead of the command line.

Just visit the release section on GitHub. The usage is pretty streight forward.

 

Changelog

 

Version 1.2.2

  • bugfix: deadlock on compiling multile files at once

 

Version 1.2.1

  • bugfix: new line after while for pretty printing
  • bugfix: build in unary function with multiple arguments

 

Version 1.2.0

  • better error output
  • concurrent compiling
  • errors are handled per file and won't stop the whole compilation
  • function name check for build in functions
  • simpler syntax for "null" and unary buildin functions

 

Version 1.1.1

  • arrays can now be declared within expressions
  • code keyword bug fix

 

Version 1.1.0

  • changed syntax of foreach
  • private function variables
  • default values for function parameters
  • added preprocessor
  • code inlining using new keyword "code"
  • some code and repo cleanup

 

Version 1.0.0

- first release

  • Like 6

Share this post


Link to post
Share on other sites

Looks nice and handy! Unfortunately I am using the function framework since A3 and it doesn't look like your compiler supports this at the moment. Maybe you should consider compiling your functions into fn_functionname.sqf files and automatically register them in description.ext or config.

This way you could even make c-like entry point functions (int main()) using preinit/postinit.

Do you plan to emulate classes in the future?

Share this post


Link to post
Share on other sites

Thanks for your feedback :)

I will consider compiling functions to their own files. Post it as an issue on GitHub if you like, so I will see and remember it.

 

What do you mean with function framework? Are you talking about the function library?

For existing SQF code, you can just call it out of ASL. Here is an example:

BIS_fnc_endMission("End1");

This should work for all library/build in functions.

 

 

Do you plan to emulate classes in the future?

Not for the near future, but I have it on my mind.

Share this post


Link to post
Share on other sites

What do you mean with function framework? Are you talking about the function library?

For existing SQF code, you can just call it out of ASL.

 

The other way around. It would be handy if ASL would be compiled into the function library. That would involve compiling every function to its own file and to a config file that gets included in desription.ext or config.cpp.

 

If you get in contact with me over Skype, Steam or Discord, I could elaborate my idea even further and share some of my experience with this kind of stuff with you.

Share this post


Link to post
Share on other sites

Something else that could help with functions whould be using the params command. I don't know how you'd implement it, but I wrote something that does it.

 

It takes this file for example (funcs.asl):

func add(_a, _b) {
    return _a+_b;
}

//Supports optional parameters too
func testFunction(_param0 = 7, _param1 = "banana") {
    return true;
}

func myFunc(_a, _b) {
    return a > b;
}

myFunc(1+3/4, 2-(66*22)/3-((123)));

And edits it in to this:

add = {
    params ["_a", "_b"];
    return _a+_b;
};

//Supports optional parameters too
testFunction = {
    params [["_param0", 7], ["_param1", "banana"]];
    return true;
};

myFunc = {
    params ["_a", "_b"];
    return a > b;
};

myFunc(1+3/4, 2-(66*22)/3-((123)));

Slight problem: It's written in Java. I took a look at your code and I have no idea how this whould transfer over to go, hope you do. Here is the source, I can try to prepare some actual pseudocode if you're interested, or I can send you the .jar if you'd want to test with it, it runs like this:

java -jar paramsParser.jar funcs.asl

Prepared it for the command line, you could run it instead of the parseFunction and parseFunctionParameter functions you have.

 

EDIT: Thinking about it, I can probably turn each of these in to a "fn_function.sqf" and add description.ext entries too.

Share this post


Link to post
Share on other sites

That's a great idea for 1.1.0 and shouldn't be hard to implement :)

I didn't knew about that command, currently parameters are just inserted into the function respecting their name.

Your code looks complicated, but I can imagen how to achive it. Thank you!

Share this post


Link to post
Share on other sites

Oh and btw local variables (local in a scope) have to be declared before usage with private command.

 

Your example should look like this:

private["_x","_y","_z"];
myFunc = {
private["_a","_b"];
_a = _this select 0;
_b = _this select 1;
if (_a<_b) then {
return "a is less than b";
} else {
return "b is less than a";
};
};
_x = 1;
_y = 2;
_x = 3;
while {true} do {
hint ([_x, _y] call myFunc);
};

Otherwise you can get unexpected behaviour when using calls to functions.

 

It would be really cool if your parser automatically scans the functions for private variables and adds them to a provate[] at the top of the scope (!)

 

params can also be used to automatically declare private variables.

Share this post


Link to post
Share on other sites

I also had some ideas for live updating code from the outside in ArmA3 for live previewing without pesky "back to editor and restart". If you want, I will discuss it with you on the weekend ;)

Share this post


Link to post
Share on other sites

@654wak654: So issue #9 and #11 are in. Was pretty easy :)

 

And code can now be inlined:

// input:
var x = code("var y = 5;"); // pass as string

// output:
x = {y = 5;};

This is useful when calling some of the buildin functions:

addEventHandler(_x)("CuratorGroupPlaced", code("spawn(_this, \"ZeusGrpPlaced\")(BIS_fnc_MP);"));

Share this post


Link to post
Share on other sites

someone else trying to reinvent the wheel

cool <3

Share this post


Link to post
Share on other sites

someone else trying to reinvent the wheel

cool <3

Too bad everyone is doing it with a different programming language and is trying to use a different syntax.

  • Like 1

Share this post


Link to post
Share on other sites

The main reason I started this project was my own dissatisfaction with SQF. So I haven't looked at similar projects.

Also, OOS looks much more complicated, which could scare some people of using it.

 

Actually, both can life side by side, OOS for larger projects and developers with more experience/professional background and ASL for smaller little scripts, easy to understand and accessable for everyone.

At the end both will result in SQF code, so they stay compatible.

 

@x39 Und nur nebenbei, es wird nicht "nur SQF mit neuer Syntax". Ich plane durchaus einige extra Features um SQF zu abstrahieren. Einiges dafür ist schon drin, z.B. Array Zugriffe, kein manuelles einlesen von Funktionsparametern usw. Was sonst noch genau weiß ich noch nicht, dafür kennen ich mich selbst nicht in den "Untiefen" von SQF aus, aber NeoArmageddon hatte da schon eine gute Idee als Issue erstellt.

Share this post


Link to post
Share on other sites

I'm just curious here and don't mean to criticise, but what is it good for? What are the practical advantages? From an advanced scripter's position I don't see any advantage in learning a new syntax, which will then be transformed to the syntax I already know in order to be compiled by the game. From a newcomer's perspective, it will be harder to understand other people's SQF scripts and code examples if I start learning scripting with ASL. We can argue about your understanding of "cleaner" (I think that's highly subjective), but I don't find it difficult to write the example from your first post in SQF:

myFunc = {
	params ["_a", "_b"];
	
	if (_a < _b) then {
		"a is less than b"
	} else {
		"b is less or equal than/as a"
	};
};

while {true} do {
	hint ([1, 2] call myFunc); // Call function, wait for it to return.
	[2, 1] spawn myFunc; // Call function, do not wait for it to return. (New thread.)
 };

Line 13 also shows something that seems to be missing in your (early) version: threading. Is there any way to include call vs. spawn in your language when calling a function? I can see the benefits of object-oriented approaches and would love to have proper OO in the game's scripting environment. Though I'm not sure whether a simple transformer is useful to me. But it might be too early to judge ASL.^^

Share this post


Link to post
Share on other sites

Well, there are a lot of reasons not to use SQF:

  • inconsistent syntax (see if () ... vs while {} ...)
  • unnecessary keywords (then, do, ...)
  • unnecessary simicolons
  • hard to read
  • access of array elements (select instead of [index])

... and more.

 

Yes it is subjective. But it depends on your background. If you started programming with Arma, you'll maybe fine with its syntax. But for people like me, coming from a professional software background, it's just annoying. The syntactical style is not convenient and does not feel natural to me.

As you may can see from the "documentation" (readme), the Arma Wiki and other scripts stay usable, as most of the build in functions can be easily translated to ASL (line 13 of your example):

spawn(2, 1)(myFunc);

I also plan more abstraction, like special functions to modify arrays (arrayC = arrayA-arrayB; isn't self explanatory), script entry points, extracting functions out of code to make them global and so on.

 

Hopefully this project will be successful enough to have its own community, explaining and helping out others :)

Share this post


Link to post
Share on other sites

Well, there are a lot of reasons not to use SQF:

  • inconsistent syntax (see if () ... vs while {} ...)
  • unnecessary keywords (then, do, ...)
  • unnecessary simicolons
  • hard to read
  • access of array elements (select instead of [index])

... and more.

 

Yes it is subjective. But it depends on your background. If you started programming with Arma, you'll maybe fine with its syntax. But for people like me, coming from a professional software background, it's just annoying. The syntactical style is not convenient and does not feel natural to me.

As you may can see from the "documentation" (readme), the Arma Wiki and other scripts stay usable, as most of the build in functions can be easily translated to ASL (line 13 of your example):

spawn(2, 1)(myFunc);

I also plan more abstraction, like special functions to modify arrays (arrayC = arrayA-arrayB; isn't self explanatory), script entry points, extracting functions out of code to make them global and so on.

 

Hopefully this project will be successful enough to have its own community, explaining and helping out others :)

 

  • That's because, contrary to if, while, waitUntil, etc. allow for expressions as well, hence the code {} bracket syntax:
    while {_a = _a + 1; _a < 10} do {...};
    
    waitUntil {_i = _i + 1; _i >= 100}; 
    
  • Programming in Java a lot lately, I actually miss these "unnecessary keywords". The if () {} else {} syntax seems illogical to me. Even if () {} {} would make more sense. I learned programming with Delphi which had the if-then-else syntax. It's all perspective in my opinion. ;)
  • Again, I find it confusing in Java that semicolons do not necessarily have to be placed after control structures. I did so much stuff in SQF and frequently switch languages during the day. By now, I end every line of Java code with a semicolon. Old habit.
  • Purely subjective and a matter of practice. And hey, it's still easier than Brainfuck. :D
  • That's where I agree. The select syntax is worth an improvent. The param/s commands help with it though.

I wish you all the best with your efforts. I'll keep an eye on this and see if interesting features come up.

Share this post


Link to post
Share on other sites

The main reason I started this project was my own dissatisfaction with SQF. So I haven't looked at similar projects.

Also, OOS looks much more complicated, which could scare some people of using it.

Well, true :P

OOS is pretty heavy and gets heavier every day (currently, for example, reimplementing the entire linker and printout so it is easier to extend and less messy) and its main goal is to be a top-level language for SQF with additional features so you do not have to check everything ingame again

 

At the end both will result in SQF code, so they stay compatible.

actually ... right now there is no easy way to execute existing SQF code in OOS as there is no way to make abstract functions yet :P

so ... its more that ASL is compatible to OOS (current state) then the other way around (to call some SQF function which is not included into your current project --> unknown to the linker, you have to use in OOS a "call compile" which is a bad overhead but state of the art sadly : /)

 

@x39 Und nur nebenbei, es wird nicht "nur SQF mit neuer Syntax". Ich plane durchaus einige extra Features um SQF zu abstrahieren. Einiges dafür ist schon drin, z.B. Array Zugriffe, kein manuelles einlesen von Funktionsparametern usw. Was sonst noch genau weiß ich noch nicht, dafür kennen ich mich selbst nicht in den "Untiefen" von SQF aus, aber NeoArmageddon hatte da schon eine gute Idee als Issue erstellt.

((quickly threw it through google translate for ya guys who might read))

@ x39 And only in passing, it is not "only SQF with new syntax". I plan quite some extra features to abstract to SQF. Some of this is already in, for example, Array access, no manual import function parameters, etc. What else exactly I do not know, but I know myself not in the "depths" of SQF, but NeoArmageddon had since been a good idea as Issue created.

Ye, saw that

but your "extra features" are more lang. flow from my perspective

still good luck on your way (btw. if you need help with your SQF understanding, just ask)

 

  • Again, I find it confusing in Java that semicolons do not necessarily have to be placed after control structures. I did so much stuff in SQF and frequently switch languages during the day. By now, I end every line of Java code with a semicolon. Old habit.
It will get more clear as soon as you start thinking why you got that bracket stuff

difference between normal programming lang. and SQF: {} is a value in SQF whilst the same is a code block in other languages

the semicolon always was just a way to "mark" the end of an expression (which is why you have no semicolons in python (for example) but have to end each expression with a new line, their code blocks are marked with the leading space btw.)

due to the difference between their usage (code block ==> multiple expressions gathered together as "one" expression | value => dont care what it is, requires assignment or usage) one requires a semicolon and one does not (code blocks already end with a '}', thus you do not need an additional ';' however, most langs do allow that additional ';' anyway)

Share this post


Link to post
Share on other sites

 

difference between normal programming lang. and SQF: {} is a value in SQF whilst the same is a code block in other languages

 

Uhm, no, {} indicates a code block in SQF as well: https://community.bistudio.com/wiki/SQF_syntax

 

Anyway, placing semicola after blocks and expressions alike became a habit for me. And since Java ignores it when not necessary, it's not much of a problem.

Share this post


Link to post
Share on other sites

Uhm, no, {} indicates a code block in SQF as well: https://community.bistudio.com/wiki/SQF_syntax

 

Anyway, placing semicola after blocks and expressions alike became a habit for me. And since Java ignores it when not necessary, it's not much of a problem.

not 100% correct

the codeblock itself is a datatype in SQF (which is why you can assign it to a variable)

Share this post


Link to post
Share on other sites

I get defending SQF's strong sides as a videogame scripting language, but Java is an actual, real programming language. They're just not comparable by some means, like where to put semicolons, or what is a code block. In Java you can use a variable if you put a code below it or above it, since they're not just parsed through from top to bottom like SQF. They're not statements or values, therefor there is no need to put semicolons after them.

 

Code in SQF is a data type:

https://community.bistudio.com/wiki/Code

Share this post


Link to post
Share on other sites

It depends on your view. Actually programming languages express logic. So SQF can be considered a "real" programming language with its use in Arma.

But, good language design looks different. I think they've choosen to stick with SQF due to their small team. I spend 30-40 hours (?) until today. And there is no optimization, no binding to the engine and so on. So it can cost a lot to rebuild that.

 

Still, I don't understand why they haven't choosen an existing language like Lua. I integrated that in one of my C++ projects. Extremly easy and secure.

On the other hand we have a reason to work on little projects like this :D

 

Btw. release 1.1.0 is scheduled for 08.11.2015, "ready or not". Means it will be tested and stable, but may not include all features I'd like it to have.

Share this post


Link to post
Share on other sites

When you say lua I immediately think of Roblox or G-mod. I'd like to think that Arma has way more capacity than those two. Plus BI essentially made all of this stuff we're using 15 years ago. Even Java or C# weren't as popular, and c++ whould give too much access to the game, it also whould be harder to master than sqf.

 

I made this btw, I'll finish it up it after update.

sNf2daP.png

  • Like 1

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×