diff --git a/index.html b/index.html index 0642e28..1a5de25 100644 --- a/index.html +++ b/index.html @@ -24,9 +24,9 @@ pre code { padding: 0px; }
The aim of this program is to act as a filter that performs the optimizations automatically, letting the programmer focus on writing readable code.
-It also implements several syntax extensions to help improving the readability of scripts and the productivity of the programmer. It works well when combined with a C preprocessor such as Boost::Wave (the one embedded in Firestorm) or cpp
.
It also implements several syntax extensions to help improving the readability of scripts and the productivity of the programmer. It works well when combined with a C preprocessor such as Boost::Wave (the one embedded in Firestorm and other TPVs) or cpp
.
Firestorm does already incorporate an optimizer. However it is limited to removing unused global variables and functions, and does so by simple string analysis, not by syntactic analysis (e.g. if a local variable with the same name as a global is defined, the global isn't optimized out even if not used). In contrast, the program presented here does full syntax analysis and implements many more optimizations, including removing unused locals, simplifying many expressions, removing dead code, and more.
+Firestorm does already incorporate an optimizer, but it is limited to removing unused global variables and functions, and does so by simple string analysis, not by syntactic analysis (e.g. if a local variable with the same name as a global is defined, the global isn't optimized out even if not used). In contrast, the program presented here does full syntax analysis and implements many more optimizations, including removing unused locals, simplifying many expressions, removing dead code, and more.
switch()
statements, for compatibility with Firestorm.identifier[index]
), for compatibility with Firestorm.cpp
and for mcpp).cpp
and for mcpp.llOwnerSay("Program version " + "1.13" + ", revision " + "b");
-The latter can also be resolved by the optimizer, but by default that optimization is disabled as it can be counter-productive.
+The latter can also be resolved by the optimizer, but by default that optimization is disabled as it can be counter-productive (see String constant concatenation below for more information).
case
labels can't appear in nested blocks. That's because they are replaced by LSL labels, and as discussed in the Multiple labels with the same name section above, label scope rules prevent their visibility in an outer block, so once converted to labels, the corresponding jump
instructions would not be able to find them. This limitation means that Duff's device or similar constructs can't be implemented with this optimizer.switch()
needs to be followed by a block, not by a single statement. For example, whiile this works in C, it won't work in this optimizer: switch(1) case 1: break;
-case
is treated by this parser as a statement, rather than as a label prefix, making break
be outside the switch
. This limitation is probably only of theoretical importance and will not have any practical implication, since single-statement switch
clauses are of little no practical use (known to the author). Of course it works perfectly when enclosed in braces:case
is treated by this parser as a statement, rather than as a label prefix, making break
be outside the switch
and failing at that point. This limitation is probably only of theoretical importance and will not have any practical implication, since single-statement switch
clauses are of little or no practical use (known to the author). Of course it works perfectly when enclosed in braces: switch(1) { case 1: break; }
switch (x) { case 1 ; default ; }
+
+
That's how Firestorm calls an extended syntax for subindex values referencing individual list elements.
@@ -237,7 +241,7 @@ llOwnerSay("Program version " STRINGIFY(VERSION)mylist = llListReplaceList(mylist, (list)value, index, index);
-However, the implementation includes creating a function that performs the replacement, which prevents the index from being evaluated twice. The function is called lazy_list_set
. It can be user-overriden. If you define a function with this prototype:
The implementation, however, includes creating a function that performs the replacement, which prevents the index from being evaluated twice but also uses more memory. The function is called lazy_list_set
. It can be user-overriden. If you define a function with this prototype:
list lazy_list_set(list target, integer index, list value)
@@ -293,11 +297,11 @@ llOwnerSay("Program version " STRINGIFY(VERSION)
The optimizer simplifies expressions as much as it knows, which is a fair amount, though there's still room for improvement in this area. Expressions that evaluate to a constant will be replaced with that constant. Most calculation functions are implemented; note, however, that the JSON functions in particular do not follow the broken LSL behaviour too closely, and that llJsonSetValue
is not implemented as of yet.
The optimizer simplifies expressions as much as it knows, which is a fair amount, though there's still room for improvement in this area. Expressions that evaluate to a constant will be replaced with that constant. Most calculation functions are implemented; note, however, that the JSON functions in particular do not follow the broken LSL behaviour too closely, and that llJsonSetValue
in particular is not implemented as of yet.
Other expressions such as a+3+1 are replaced with a+4, and so on. Note, however, that for floats, (a+b)+c
may not equal a+(b+c)
, so that optimization is not always done for floats. Also, as of this writing this optimization is only partial, so some expressions may not be optimized, e.g. 2+a+b+3
is not optimized to a+b+5
. Many boolean expressions are simplified too (more are on the way). For example, (TRUE&&(expression))
is simplified to (expression)
, and (FALSE&&(expression))
is simplified to (FALSE)
provided the expression has no side effects. The famous if (llListFindList(...)!=-1)
to if (~llListFindList(...))
replacement is also performed automatically.
The constant folding optimizer is also responsible for simplifying certain statements, e.g. if (FALSE) { statements; }
is completely removed, and if (TRUE) { statements1; } else { statements2; }
is replaced with just { statements1; }
, removing { statements2; }
. Similarly, do...while(constant)
loops and other loops are optimized too.
The constant folding optimizer is also responsible for simplifying certain statements, e.g. if (FALSE) { statements; }
is completely removed, and if (TRUE) { statements1; } else { statements2; }
is replaced with just { statements1; }
, removing { statements2; }
. The do...while(constant)
loops and other loops are optimized similarly.
This enables using many preprocessor tricks, like creating an assert()
macro similar to that in C:
Long variable and parameter names are nice and readable, but when used as part of the globals or as function parameters, or in function or state names, each character in the identifier takes at least one byte of code memory. In large programs, this can add up to a significant amount. This option replaces global (including functions and states) and parameter identifiers with the shortest possible ones, also reusing as many as it can. The savings from this alone can be very significant in programs with a large number of globals or states.
+Long variable and parameter names are nice and readable, but when used as part of the globals or as function parameters, or in function or state names, each character in the identifier takes at least one byte of code memory. In large programs, this can add up to a significant amount. This option replaces global (including functions and states) and parameter identifiers with the shortest possible ones, also reusing as many as it can as well as reusing some system ones. The savings from this alone can be very significant in programs with a large number of globals or states.
The sign at the beginning of a number (except in globals) takes one byte of code, unless prefixed by a type cast (which does not, under Mono, take code memory in itself if the destination type is the same). Small saving, but it adds up to the overall. Numbers are thus output with a type cast and surrounded by parentheses, e.g. ((float)-1.5)
instead of -1.5
.
The sign at the beginning of a number (except in globals) takes up one byte of code, unless prefixed by a type cast (which does not, under Mono, take up code memory by itself if the destination type is the same). Small saving, but it adds up to the overall. Numbers are thus output with a type cast and surrounded by parentheses, e.g. ((float)-1.5)
instead of -1.5
.
Since Mono keeps only one copy of each constant string in the code, making the optimizer concatenate them would be counter-productive, generating two long strings that take more code than the original string plus the shorter ones.
+Since Mono keeps only one copy of each constant string in the code, making the optimizer concatenate them would be counter-productive, generating two long strings that would take more code than the original string plus the shorter ones.