Victor Kohn (Kurchatov Institute), URL: http://kohnvict.narod.ru, 27-12-2024
ACL - advanced command language - input language of the ACL interpreter program
Program URL: http://kohnvict.ucoz.ru/vkacl/ACLnews.htm
PC - a computer with a large screen and a resolution of 800 * 600 or more
The ACLP.jar program for a PC is written in Java SE 6u0, URL: http://java.sun.com
.
1. GENERAL INFORMATION
The ACL programming language was invented in 1992 for PC AT-286 computers running DOS. Then there was a need to somehow manage a large number of already written subroutines in the Fortran language. Using libraries at the compilation stage turned out to be ineffective and I wanted to have just a pure interpreter, so that like two out of a sack: wrote and immediately executed. It so happened that ACL in its structure turned out to be a macro language, which just corresponded to the goal. With the advent of Windows, the old interpreter - a DOS program - lost its relevance. Ten years later, I took it upon myself to revive ACL, first with the goal of using it on a pocket PC, since I had not found any good programs for calculations on a pocket computer by the time I wrote my program. And there are none now. To write the interpreter, I used the Java language in a modification for virtual machines of the Ewe project. These VMs were given free of charge with the right of free distribution, which is naturally attractive. In fact, it was necessary to rewrite the old code from Fortran to Java. But it turned out so well that I decided to make a separate version for implementation on a PC and using the standard Java SE 4u2 language. This was the last version at the time I started working. Subsequently, both versions began to differ slightly due to the different capabilities of the pocket PC and the PC. But the main structure of the language is still common. I will write about the language for the PC, the language for the pocket PC actually died along with the Windows Mobile OS, where it worked.
The basic structural units of the ACL language are commands, parameters and arguments. A typical ACL program is a set of commands to execute as in any DOS or UNIX command files, although in my case the arguments of some commands have a very complex structure and themselves can have commands. In the program text, there is no binding of commands to lines, and comments are normal text. Commands can be located between such normal text in any place. In other words, comments are written naturally, and the program is like oases in the desert. The interpreter skips the text in the file until it finds the symbol [#]. I will place the necessary symbols in square brackets to separate them from the text. This symbol indicates the beginning of the command. After it, the command name must be typed without spaces. You can write an arbitrarily long name, but the interpreter will take into account only the first letters. For some commands, one letter is enough, for some commands 2 letters, but for all commands no more than 3 letters. The number of commands is not limited in principle, but there are 37 of them so far.
After the command name, separated by a space (with rare exceptions), the presence of a special parameter definition field is checked, I call it FPD (field of parameter definition). This is a certain set of assignment operations for defining parameter values, limited by square brackets. There are 4 text parameters, the values of which are character strings, the other parameters are integer variables, the values of which are integers. All parameters have names. The same story with parameter names - only the first letters are important, although the name can be long, if someone finds it more convenient. Once defined, a parameter retains its value until it is redefined. You can define and redefine any parameters in the FPD of any command. When you start the program, all parameters are defined. Therefore, if you have not defined a parameter, the command will initially work correctly, but then, after this parameter is redefined, there may be errors. Therefore, it is better to define all parameters used by a given command in its FPD, or at least monitor their current value. Finally, after the FPD, you must write the command arguments if the command definition requires it. Unlike parameters, which have names and can be defined as many times as you like, arguments are read only once and are values. Therefore, arguments must always be defined. Arguments are specified without brackets.
But it's not that simple. Among the text parameters, there is one special parameter called [operation] or, for short, [op]. This parameter specifies which operation this command will perform from among the possible ones. The number of operations for each command is also, in principle, unlimited and depends only on the language version and the performance of the interpreter author. Depending on the type of operation, the command can use different parameters and arguments. That is, the same command can have a different structure. As is known, object-oriented languagesstill have static classes that work with static memory. The ACL language is partially similar to a language with static classes and static memory. Commands are similar to static classes, and operations are similar to static methods of classes. According to the laws of the genre, there must be static memory.
Indeed, in the ACL language, the memory is common for all commands in all parts of the ACL program, that is, static. Modern languagescan operate with temporary memory, which is dynamically created and dynamically removed. On the other hand, the PostScript language does not have memory in the usual sense at all - only a stack. ACL implements an intermediate variant, which is most suitable for the main purpose of the language - organizing calculations using ready-made blocks. Using an interpreter at the micro level for super-complex calculations with a large number of code repetitions is unreasonable due to a sharp decrease in the speed of operations due to the need to interpret each command again and again. But the interpreter has its advantages, and they are just useful to use. And static memory is also useful in this case, since you do not need to think about transferring data from one ACL procedure to another.
And again, simplification. I do not like to strain my brain inventing and remembering variable names. Therefore, at first I made only single-letter variable names from [a] to [z], then from [A] to [Z] and additionally special variables [$] [%] [&]. A total of 55 variable names. Moreover, upper and lower case letters mean different variables. But then I expanded the number of variables, which is still necessary for organizing fairly complex calculations. As practice has shown, the ACL language turned out to be quite capable of performing complex analytical analyzes quite quickly. Therefore, I additionally introduced variables whose names have two symbols - a letter and a number, i.e. a0, b0, ..., z0, a1, b1, ..., z9, A0, ..., Z9. A total of 520 additional variable names. This was once the case in BASIC for the first primitive personal computers on which I managed to work. Well, and many years later I introduced a third type of variables consisting of two letters. There are already 55 * 55 = 3025 names. In addition, there is one integer array i (149999) , one real array r (25999999) and one text array t (1999999). The array element index is specified in parentheses, the maximum element of the arrays is specified above, and the minimum starts with one. In addition, there is a service array s(112) . This is the same array of integer parameters that have names. However, not all elements of the array have names. The service array can be used to define named parameters in an alternative way, that is, using commands instead of defining them inside the FPD. Some elements of the service array are used to regulate the operation of commands directly, that is, without using names. The names for the elements of the service array, that is, the parameters, are introduced simply to make the code easier to read, since they suggest the functional meaning of each element.
Despite some limitations, this language structure allows you to create programs of any complexity that can work as interactive and multi-window applications, and in any operating system. They can use all the resources of the most modern computers, since the interpreter is written in Java, and uses almost everything that Java offers.
.
2. FIRST COMMANDS
How it looks in practice. First of all, there is an end command
#stop
which finishes reading the file and executing commands, even if there are still ACL commands left in it. This is convenient, as it allows you to store pieces of programs for examples and tips in one file. If there is no such command, then the file is read to the end and the program ends naturally. There is also a command
#exit
which allows you to terminate the interpreter. It is only necessary when starting the interpreter with a fully prepared ACL program, when the ACL program debugging environment is not used at all in the interpreter. This allows you to present the ACL program as an independent program, the use of which does not require knowledge of the ACL language. Further, the language contains descriptions of the procedure
#pro NAME (all other commands go here) @
The [@] symbol serves as the end of the procedure (bold dot). The name of the procedure NAME is the first argument of such a command. It must contain 4 characters in any combination. Any piece of the program can be preliminarily placed in the procedure body (it is not executed, but remembered). The procedure body and the ending symbol [@] can be considered as the second argument. This code will be executed later. The order of recording on the line does not matter. You write it as conveniently as you like. Procedures are executed using a special command, which should naturally be placed after the procedure definition
#e [c=1;] NAM1 NAM2 NAM3 !
This command means to execute procedures one by one from the specified list. If the #pro command has only arguments: [NAME] and the procedure itself, then the #e command, in addition to arguments, already has a parameter named [c] (code), the value of which can be assigned right here in FPD, or even earlier. All procedures are executed only if the value of the [cod] parameter matches the current value of the [&] variable. This variable must be defined in advance. But if you write
#e [c=&;] NAME !
then the procedure will always be executed for any value of [&]. For brevity, the same can be written as
#e_NAME !
The underscore before the first name in the procedure list means unconditional execution. It is important to remember that [c] is an integer, and [&] is a real variable, so its nearest integer is used for comparison. The list of names ends either at the next command, that is, the [#] symbol, or the procedure end symbol [@], or at the special symbol [!] if the list is followed by simple text.
This command is additionally reinforced by two special modes necessary for writing especially complex programs. The special procedure names [file] and [text] are used to execute program commands from a file or from a text array t(). Example:
#e [file=0/calcul.acl;] _file !
This command specifies that a procedure should be executed, i.e. a set of commands written to the file "calcul.acl" placed in the folder "0" relative to the interpreter folder. The interpreter was originally specially made so that it did not work with external folders, but worked with folders inside the "zero" folder, i.e. the folder in which the interpreter itself is located. (Folder) is the place where files are stored, its other name (Directory) was used in DOS, I switched to the window language. Here the second text parameter [file] is already used to specify the path to the file. In this command, the full path to the file is specified, i.e. relative to the "zero" folder. An even more complex command
#e [b=a; le=b;] _text #%
allows you to execute commands dynamically written to a part of the text array t(), starting with the element t(a) and with a length of b characters. The concept of a text string does not exist in ACL. Any string, as we know, consists of a set of characters and has a name and a length. The valuesof the numeric parameters [b] (begin) and [le] (length) can be considered as the name and length of the string. It's just that in ACL the string name is also a number that specifies the placement of characters in the text array. This is quite sufficient. The program that this command executes does not initially exist, so it must be recorded in advance. Naturally, the [c] parameter can also be used in both cases. The recorded version of unconditional execution is simply shorter. Finally, it is necessary to note one important property of this command, which I have already written a little about above. It reads the names of procedures for execution indefinitely until it encounters the [#] symbol or the [@] symbol, which denote the beginning of a new command or the end of a procedure. If it is necessary to insert comment text after the command or this command is the last one in the file, then any other command with a fixed length can be put after it. But for brevity, the symbol [!] was introduced, which also stops reading the list. The shortest command is #%, so I used this command before. Its real meaning is sending the current symbol number of the program text to the variable [%] for subsequent use for various purposes. But in this case, it simply acts as a limiter for the previous command. If this is not done, the interpreter will return an error of a non-existent procedure.
As is obvious from what has been said, you must first define all the procedures, and then write the text of the main program. Sometimes this is inconvenient, since you have to start studying the program from the end of the file. But you can use a simple technique. The main text of the program is also placed in the procedure
#pro main ... @
Now you can write any procedures in any order, and at the end of the program write a standard line
#e _main #stop or #e _main !
The second option is necessary if the program is written to a file and is part of a more complex program, so stopping is undesirable. It is not necessary to look at the last line. In this form, the entire program consists of procedures.
.
3. PRINTING AND VIEWING TEXTS
The text array t() is an array of characters, but not old ASCII characters, but Unicodes (double-byte characters). You can enter (write) characters of any language (Unicodes), numbers in text format, just text, and much more into its elements. To write to a text array, there is a command
#print FT (in short #pr FT)
It has one argument called formatted text (FT). FT is generally a complex formatted text consisting of both plain text and text commands (formats). Formats, like in Fortran, are absent in Java, this is a small matter and the creators of Java believe that formats should be done by programmers themselves. But not everyone is interested in making formats, and it is also inconvenient in fast programming languages, such as ACL. Therefore, I made many different formats, for all occasions, but if someone says that they are missing something, I can easily make other formats, I have no ideas yet. For now, there is everything that I personally need for the programs that I have already written.
First of all, it is important to know that FT always ends with an end sign, that is, an end command. All format commands begin with the [\] sign, followed by one letter (the command name), and then there may be arguments. The end command looks like \E, for example, the command
#pr ab cde \E
will print the text "ab cde " into the text array t(). As you may have guessed, the text begins with any character other than a space. That is, in this mode it is impossible to write spaces at the beginning of the text. How to do this will be discussed later. All calls to the #pr command print record after record in t() sequentially, starting with t(1). But this natural order can be changed. In reality, the number of the element of the t() array, starting with which the next record will be made, is determined by the element of the service array s(3) without a name. The value of this element, unlike elements with a name, automatically changes with each record. But this value can also be changed manually by equating s(3) to any value before executing the #pr command. In addition, for ease of use of records, after each execution of the #pr command, the element of the service array s(4) contains the beginning of the record made, that is, the index of the first element of the text array, and s(5) is the number of written characters. The next command is the command for writing elements of the text array itself into the text array. It has two arguments.
#pr ab \T(b) (l) cd\E
Here the arguments (b) (beginning) and (l) (length) contain information about the first element of the text array and the length of the text string to write. These can be integers, variables, or elements of numeric arrays. Again, I note that after the \T command (or rather after all commands), spaces are ignored and subsequent plain text begins with any character other than a space. For example,
#pr ab \T121 10 cd\E
will write the following text [ab t(121)...t(130)cd]. You have already guessed that such a text command allows you to perform any manipulations with text lines, although the concept of a text line does not exist in the ACL language. This is especially useful in loops.
The next series of commands are commands for writing valuesof numeric variables to a text array. The simplest of them \G can have any number of arguments separated by spaces. The list of arguments ends with the [;] character. For example, the correct command
#pr \G abcd;\E
Here a, b, c, d are numeric variables. For example, let a=345; b=0.001; c=2.E-4; d=0; After executing the above command, the following text will be written
3.4500+02 1.0000-03 2.0000-04 0
That is, the \G format is a general or standard format that writes all numbers into a string of 11 characters with five significant digits, a decimal separator in the form of a dot and an unsigned exponent E. I noticed that the E sign is necessary when specifying numbers in mathematical expressions, but when printing numbers separated by a space, it is unnecessary and can be omitted. This format is convenient if you need to get the valuesof numbers, and the style is not important to you. However, if the style is important, there is another command
\N(t) (f) abc; ,
which has two additional format arguments. Here (t) is a number indicating the total number of digits when printing numbers, and (f) is a number indicating the size of the fractional part when writing numbers. The exponent is missing. Everything else is as in the \G command. Obviously, (t) must be greater than (f) by at least two positions + the length of the integer part of the number. However, there are special cases. If (t) is 0, then the length of the number is minimal and depends only on the size of the integer part. If (t) is -1, then this command is equivalent to \G. Historically, the \G command was introduced later as a replacement for this mode. Additionally, there is another format
\B(t) (f) abc; ,
where the arguments have the same meaning as in the \N command, but the number is written with one whole digit and with a power of ten after the letter E. In addition, in this format the decimal separator is a period instead of a comma. This format is necessary for the compatibility of data recording with other programs. In some programs, it is convenient to insert integers with a fixed number of digits into the text. For this, there is a command
\I(n) abc; ,
where n is the total number of digits allocated to the number. If it is positive, the extra digits on the left are filled with spaces, and if it is negative, with zeros. In the latter case, the number of digits shows the modulus of the argument n. In some special cases, the command is used
\S a; ,
which writes a number with the minimum number of digits and, in addition, rounds off the last significant digit to eliminate calculation errors. For example, the number 2.49999234 will be replaced by 2.5 in the same way as the number 2.50000123. Formally, this command is also applied to a list of variables, but in reality it is reasonable to use it only for one value, since two valueswill be written together (without spaces). This command is useful for marking graph axes and in general on graphic drawings, as well as in input windows. This was the case at the very beginning, then I still surrounded the numbers with spaces.
The next command is to print characters by their Unicode. Unicodes, as is known, describe the signs of any language. Whether they will be printed depends on the capabilities of the font used. But they will definitely be entered and can be manipulated. The first 128 Unicodes coincide with ASCII codes. The command looks like this
\U nnn*mnn; .
Note that the space after the letter U is optional. The n*mconstruction means that the Unicode with number n will be printed m times. The list ends with [;]. Now it is clear that 5 spaces at the very beginning of the text can be entered as \U32*5; . There is also a system of simpler commands for entering service characters into the text, namely
\b (backspace) \t (tab) \n (line feed) \r (carriage return) \' (character ') \" (character ") \\ (character \) \@ (character @) \# (character #) \[ (character [) \] (character ]) \- (nothing).
These commands, except for the last one, enter the characters that are specified second, since directly writing these characters will lead to incorrect interpretation and errors. The last command \- does nothing at all. But it is still necessary, since not only spaces, but also line breaks are ignored after each command. It is inconvenient to type a very long text in the argument of the #print command on one line and it is reasonable to transfer it. But then the line break sign will be written. To prevent this from happening, you need to type \- before the break and then the line break signs will not be written into the text, and the command itself will not add anything. But if you really need the line break sign to be written, then write it boldly in several lines - that's how it will be printed.
Finally, there is another command
\D ,
which inserts the current date and time into the text according to the data on the computer, there is a command
\P(n) ,
which inserts the value of the text parameter. There are 4 text parameters, but initially there were 6, so they have numbers with a jump. You can say that two numbers are reserved. So [fir] (first) has number 1, [op] (operation) has number 4, [file] and [form] (format, formed) have numbers 5 and 6 respectively. And there are also comment brackets
![...]! .
Both the brackets themselves and the text inside them are ignored and not written. A comment can be put after any command before the regular text. But in reality this is already excessive and is necessary only in very rare cases. I myself do not put such comments. However, if there was an opportunity, and everyone will figure out how to use it themselves.
As I have already noted, such a set of formats allows you to cover all the necessary situations. Over time, other formats were made, but you can see this in more recent documents. And this document was written at the very beginning. The text array can be viewed after executing the program from the shell menu [Execute//Show textarr], since after executing the program, the written part of the text array is saved to a file called "textarr.txt". This file is shown in the text editor. The size of the written part of the text array is determined by the s(6) parameter. If a lot of text is written to the text array and you do not want to write it to the "textarr.txt" file, since this takes time, then you can simply reset this parameter before the end of the program.
There is another way to display formatted text without writing it to a text array. This is done with the #message command or, for short, #m. This command displays formatted text in different ways depending on the value of the [op] parameter. If the command is given
#m [op=txt;] FT,
then the text will be shown in the text editor window, which accompanies the program and is called "Terminal". All modes of this command show the text during the program operation, just when it is executed. If
#m [op=rtt; n=1;] FT,
then the text previously typed in the terminal will have as many characters deleted as the value of the [n] (number) parameter (in the shown variant, 1) indicates. In this case, the argument is not used, but it must still be present at least in the empty form \E to comply with the syntax. This mode allows you to control the degree of execution of a certain procedure in a loop. You can first print a certain line of text, and then, as the loop executes, cross out characters, that is, make a countdown. If
#m [op=win;] FT,
then the text will be shown in a separate window and the program will stop running until the user presses the [OK] key. If
#m [op=oce;] FT,
then the text will be shown in a special window containing three keys [OK] [Cancel] {Edit] and the number of the pressed key will be equal to the value of the special variable [&]. If
#m [op=yno;] FT,
then the text will be shown in a special window containing two keys [Yes] [No] and the number of the pressed key will be equal to the value of the special variable [&]. Finally,
#m [op=uni;] FT FT,
(this command has two FT arguments) displays a message in a window whose attributes are defined by the second FT argument. This argument must contain several texts separated by a vertical bar [|]. The first text is the title of the window itself, and the rest are button titles, the number of buttons will depend on the number of recorded texts. The number of the pressed button in the range from 1 to the number of the last button is returned in [&].
The #m command (one letter is enough) is one of a series of commands that implement the user interface. It allows you to communicate various information and ask questions. It can be used to organize reference books, card files, etc.
.
4. CALCULATIONS
Now about mathematical calculations and functions. All calculations are done in that part of the program text that is the argument of the special command #calc or #ñ. There is another version of this command, when it can be written without a name at all, since given the frequent use of this command, an exception has been made for it. It has no parameters, and its argument is a set of assignment operators. For example,
#a=1; b=sin(a); c=b<2; i(5000)=&;
So, two signs [#] (the space after the hash is mandatory) open the field of assignment operators with the construction (name)=(value); and the spaces between these elements can be in any quantity, including none. You can write everything without spaces at all. This field ends either with the sign [#], that is, the beginning of a new command, or with the sign [@], that is, the end of the procedure. You can put comments of a special construction, but it is easier to break off the field with the symbol [!]. We have already seen this symbol when describing the execution of procedures. Here it is used with the same meaning. All standard operations are available for performing calculations
+ - * / ^ ( )
written in reverse order of execution. The ^ sign means raising to a power. And there are standard functions. The latter have names consisting of three signs. The list of standard functions is supplemented by some special functions. It is listed below:
abs() [absolute value] sqr() [square root] log() [natural logarithm] exp() [exponent] sin() [sine] ars() [arcsine] cos() [cosine] arc() [arccosine] tan() [tangent] art() [arctangent] rnd() [random value] int() [integer part] sfi() [Fresnel sine integral int(0,x)dt*sin((pi/2)*t^2)] cfi() [Fresnel cosine integral int(0,x)dt*cos((pi/2)*t^2)] bj0() [ Bessel function J[0](x)) ] bj1() [ Bessel function J[1](x)) ]
The argument of functions is written in parentheses in the same way as the indices of array elements. The rnd() function does not use an argument, but to comply with grammar, you must write rnd(0). Numbers can be written in any format, both with a period and with a comma, and in exponential form with both [E] and [e]. Here are examples of correctly written numbers:
1.23 1.23 12.3E-1 0.123E1 123e-2
But ACL has a feature that distinguishes it from other languages, namely, two new operations a<b and a>b have been added . They mean the smaller of two and the larger of two. Usually this is done by a function of two variables, but in ACL there are no functions of two variables, and the minimum and maximum are implemented by an operation. For example, a<1 means [a] if [a] is less than one, and 1 if it is greater. The priority of these operations is higher than all others, except for brackets. That is, all complex parts of these operations must be in brackets.
Two more simple but useful commands naturally adjoin the calculation command. The first of them
#d N r(11) abc*5 g ...
The name of this command is (data), but one letter is enough. It allows you to quickly determine the valuesof array elements. The first argument (N) determines how many elements will be determined, the second simply specifies the first element of the array to determine. In fact, this entry specifies both the array type and the first index. It is important to keep in mind that variables also form an array, specially ordered, so they can also be defined in this way. And then come the values??that need to be assigned to the array elements. These can be numbers, variables, and array elements. If there is *5 after the value, this means that this value must be taken 5 times. So, the arguments of the command form the following structure: (number)(beginning of the array)(data). But there can be any number of such structures, one structure follows another. The end is again either on the [#] sign, or on the [@] sign, or on the [!] sign. Everything else is treated as an error. The number N is limited and cannot be more than 500. There is also a reverse command, its name is v and it sends values??from the array to the variables. Second team
#pas N r(11) i(25)
allows you to quickly assign valuesfrom the elements of one array to the elements of another array, as they say, to send valuesfrom one array to another. If the arrays have different types, then the type conversion occurs in parallel. The first is the array from which the valuesare sent, the second is the one to which they are sent. For example, in the example given, real numbers will be rounded to the nearest integer. The structure is not repeated in this command. You must write the command name again. The number N is not limited.
.
5. CONDITIONAL EXECUTION
As a result of introducing the [<] and [>] operations, it became possible to abolish all the so-called conditional operators, leaving only a block of two commands. Namely
#case N. . . #end
Here N is the argument of the #case command -- it is a number, variable or array element, and the ellipsis denotes all other commands that are executed only if [N=&]. The #end command limits the code of one variant and performs additional analysis, and [&] is again a special variable that plays an important role in interactive windows. The simplest logical operation that can be implemented using this command is branching. Let's say we have several code variants, of which we need to execute one. This is done with a set of commands
# &=2; #case 1 . . . #end | #case 2 . . . #end | #case 3 . . . #end | and so on.
In the written code, the second option will be executed. It is enough to change the value of the variable [&], without touching the rest of the code, and the new option will be executed. But the command pair #case N ... #end is also a universal description of a cycle, that is, multiple repetition of a certain sequence of commands. The fact is that the condition [N=&] is checked not only when executing the opening command #case but also when executing the closing command #end. If this condition is met again, then all the commands of the body (that is, what is in the ellipsis) are executed again and so on ad infinitum. In this case, the value of N (the argument of the command #case) can no longer be changed, the arguments are read only once, but the value of the variable [&] can and should be changed. To make it easier to write such a change, the construction #end | (with a vertical bar through a space) first performs the operation [&=12345;], and then checks the condition. There is also an option #end (a), when the operation [&=a;] is performed before checking the condition. But I almost never use this option. Although sometimes it is easier than defining the variable [&] again. You just have to get used to it. This pair of commands does have a difference. The thing is that the #case command checks the [N=&] condition on exact real numbers, while the #end command only checks on integers, i.e. only the integer parts of both numbers are compared. Generally speaking, it makes sense to check all conditions on integers, since rounding errors may occur in real numbers. But nevertheless, you should know about this feature. Let's look at an example,
#i=0; &=i; #case 0 . . . . # i=i+1; &=(5-i)<0; #end
Here the ellipsis will be executed for i=0,1,2,3,4,5 and then the cycle will end and the program will proceed further. In such a construction #case works as a simple cycle. But for convenience there is also a simple command for these purposes
#rep N . . . #end
which simply repeats the ellipsis N times. The #case command actually allows you to execute or not execute something depending on any logical condition. You only need to correctly define the variable [&] using the [<] and [>] operations. That is, it alone replaces the if(){} operator, the while(){} operator, and the switch(){} operator of the Java language, as well as similar operators in other languages. And at the same time, it does not impose any restrictions on programming capabilities.
.
6. FIRST RESULTS AND GENERAL INFORMATION
Let's summarize the first results. We have variables, arrays and texts. We can assign valuesto variables, perform calculations in cycles and depending on various conditions, we can write all this down as text and show it on the screen as messages. Not so little for performing calculations, designing tests, even writing information cards. But the arsenal is not complete. Even the very first and primitive programming languages??like BASIC and FORTRAN could write and read data from files. True, in our case, unlike compiled languages, the program text itself can contain everything necessary that is usually written to files. But the thing is that you need to be able to operate files written in a special format or other programs. And more advanced modern languagescan also create tools for graphical communication with the user. Don't worry. ACL has all of this and even a little more than other basic languages. But you need to learn how to use these tools. And this is not always easy, since it requires knowledge of how the computer works, the operating system, the structure and methods of writing files. There is still a lot of work ahead and it must be done gradually and systematically. But before we continue, let's list the commands that we already know.
stop | exit | pro | e | pr | m | c | d | v | pas | case | end | rep
and discuss some details of the organization of RAM (random access memory) and HD (hard disk) memory. The first is the computer's RAM, it works only when the computer is on and disappears when it is turned off, the second is the memory on hard drives, which can be transferred from one computer to another and stored for a long time. The ACL language is just a set of data for a program written in the Java programming language. Therefore, it operates with the same data types as Java. Java defines the following data types: byte - signed integers of 1 byte in length and 2 7 = 128 modulo short - signed integers of 2 bytes in length and 2 15 = 32678 modulo int - signed integers of 4 bytes in length and 2 31 = 2147483648 modulo long - signed integers of 8 bytes in length and 2 63 modulo float - signed real numbers of 4 bytes in length, with a precision of 7 decimal places double - signed real numbers of 8 bytes in length, with a precision of 15 decimal places char - two-byte characters - Unicodes. In reality, for positive numbers the modulus is one less, since there is also zero. In the ACL language, variables and elements of a real array are of the double type, and elements of an integer array are of the int type. Elements of a text array are of the char type. Other data types are not used in calculations, but can be used when writing to files.
As for the file structure on hard drives, it is divided into disks, usually designated by one letter (a-floppy disk, b-second disk drive, which is very rare now, c-system part of the hard drive, d-software part of the hard drive, but not always, the remaining letters designate compact discs, flash memory, and so on). Each disk has a set of nested folders, inside which files can be located parallel to folders. Therefore, the file name can be either short (the name itself) or long (that is, the path to the file). A short file name may contain one or more periods. The part of the name after the last period is usually called the name extension and is used to determine the file type. For example, exe - for an executable file, acl - for a file with the program code in the ACL language, java - for a file with the program code in the Java language, jar - for a file with an archive of the program code in Java, and so on. For example, aclp.jar is an archive of Java program code and simultaneously an executable program -- the ACL interpreter.
The full path to the Java file (and ACL) is written as C:/firstfolder/secondfolder/thirdfolder/file but you can write a shortened path relative to the file of some program. Let, for example, the file aclp.jar have the following path C:/_vk/ACLp/aclp.jar Then the shortened path relative to this program for a file located in any folders inside the program folder will be one in which C:/_vk/ACLp/ is not written. Previously, only shortened file paths were used in ACL, that is, all used files MUST be located in the interpreter folder or in more internal folders. Moreover, ACL has the concept of a "working folder" that can be defined in advance, and then the file names of many commands are counted from this working folder. The latter can be redefined during program execution. And the working folder with the name null was used precisely for the interpreter folder. Then, however, an exception was made, and if the working folder is null and the second character in the file path is (:), then the full path of the file on the computer is used. Well, this information is quite enough to move on to the commands for working with files.
.
7. FILE OPERATIONS
The #d command described above defines array elements by values. But it is often useful to write valuesto a file and then read these valuesin another program or in the same one, but on another day. Such operations are performed by the command
#io [op=; fir=; n=; file=; form=; mo=; le=;]
It uses 4 text parameters and one numeric parameter. The [op] parameter specifies the type of operation, which is encoded by two letters. The first letter can be: [r] (read - read from file) or [w] (write - write to file). The second letter can be: [f] (format - write numeric valuesin text according to format) or [b] (byte - write data of byte type) or [d] (data - write data of float, int or double type) or [t] (text - write text data). So the following operations are possible:
rf wf rb wb rd wd rt wt
Next, the [fir] (first) parameter is equal to the entry of the first element of the array, as it was in the #d and #pas commands, that is, both the type and the first index are specified, for example, r(35). The [n] (number) parameter specifies how many elements should be written or read. The [file] parameter specifies the path to the file relative to the "working folder". If the working folder is specified correctly, then the file name is enough. There is a limitation here -- the value of the [file] parameter cannot be longer than 42 characters. So do not get carried away with long names. If the file name is longer, it will have to be renamed. It is useful to discuss two different ways of specifying text parameters here. They can be specified in plain text, for example, file=mydata.dat; and the text must end with the [;] symbol, like all assignment operators. But they can also be specified as formatted text. But in this case, the first character must be the text format symbol [\] and such a line must end with the characters \E without a semicolon. Although all text parameters can be specified this way, this mode is mainly used only for specifying a file and mainly by specifying a text link. This is very convenient in loops. Let's say you need to read 50 files in a loop with the names: img01.png, img02.png, . . . , img50.png. Then the code can be like this.
#m=0; ... #pr img\E # a=s(4); b=s(5); #rep 50 # m=m+1; ... #io [op=rb; fir=i(1); n=256; file=\Ta b\I-2 m;.png\E] #end
Naturally, a file specified by text should not begin with the [\] character. But this limitation is very weak. This technique is called dynamic file name generation. More complex file names can be printed first, and then specified by text links, generating the link index (string name) by the cycle parameter. The [form] parameter (format - the format for recording numbers in text) is used only in one operation [wf], that is, recording by format. In the [rf] operation, that is, reading by format, all possible formats are automatically read and there is no point in specifically specifying the format. But the format is still used to transmit other information. It must have a structure
form=*N;
where N should be a number or a variable with an integer value that specifies how many lines in the file will be skipped before reading numbers begins. Writing numbers by format is possible only from the i() and r() arrays. If you need to write numbers from other arrays, you must first send them to these with the #pas command. The [form] parameter is also limited in length to 42 characters, but all possible formats have a shorter length, so this limitation is formal. The simplest format is this
form=*N;
where N should be replaced by a number indicating how many numbers should be printed on one line. This format is equivalent to the text format \G (see above about text formats). The end-of-line indicator will be ASCII code 10, that is, as in the UNIX operating system and as in Java. There is also a second format, which has the structure
form=EN.ML;
where N should be replaced by a number indicating how many numbers should be printed on one line, M should be replaced by a number indicating how many positions (characters) should be allocated for one number, L should be replaced by a number indicating how many positions are allocated for the fractional part of the number. The dots between the numbers serve as separators. In this format, the line ends with two ASCII codes 13,10, and the numbers are written in scientific notation with E and the decimal separator is a dot. It is necessary that M be greater than L+7. This format is equivalent to the text format \B. For example, 6 numbers written in the format [form=E3.10.3;] will generate the text
1.000E+00 2.000E+00 3.000E+00 4.000E+00 5.000E+00 6.000E+00
There are no more formats. But in reality, you can organize an arbitrarily complex format if you first write the text to the text array t(), and then copy it to the file.
So, let's move on to the operations [rt] and [wt]. These operations can only work with the text array t(), so the parameter [fir] must point only to t(), otherwise there will be an error. The operation [rt] simply fills some part of the array t() from the file, starting with the element specified by [fir] and exactly [n] elements. In this case, the entire file is first read as text line by line, then the contents are converted to an array of Unicodes and the required number of characters is taken. This mode was tested only on the first 127 Unicodes and how it works on the rest can be tested experimentally. After the operation, the parameter s(4) contains the index of the first element written in t(), and the parameter s(5) is the number of elements. This is the general principle of writing to a text array, the #pr command does the same. At any time, the s(6) parameter shows the size of the recorded part of the t() array. The [wt] operation, on the contrary, first converts the required part of the Unicode array into text and then writes it to the file line by line. In this case, the file is written in its entirety, and if it existed before, it is completely rewritten. In this case, the end-of-line indicator corresponds to the operating system that is used. For example, in Windows it is [13,10], although initially the text array was simply [10]. Now it is clear that the image of the future file can be formed using the #pr command and then transferred to the file from t() in its entirety. In this case, you can use the full power of the #print command formats.
The [rd] and [wd] operations allow you to read and write numbers in computer code. This is the most compressed form of recording and is especially useful for writing very large arrays. In this case, the [mo] (mode) parameter is additionally used to specify the format of recording numbers. If [mo=1;], then the numbers are written and read in the "float" format, that is, real numbers 4 bytes long. If [mo=2;], then the "int" format of integers 4 bytes long is used. Finally, if [mo=3;], then the "double" format for real numbers 8 bytes long is used. The byte order is the same as in Java, that is, the most significant ones are on the left. For Windows system data, you must first reverse the byte order using some special procedure. The ACL program itself both writes and reads and there are no problems. The data is read from the file not from the very beginning, but after skipping a certain number of bytes specified by the [le] parameter, and not the entire file, but as many numbers as specified by the [n] parameter. But the numbers are written to a new file from the very beginning. If the file exists, it is rewritten. You can find out the size of the file when reading using the #file command (see below). If the program reads more data than was written, the error that occurs is not blocked and the Java interpreter program will display a message in the Terminal. So you have to be careful. This is a flaw, I confess. You should understand that the [le] parameter allows you to skip any amount of data before reading. But it is the number of bytes that is specified, not numbers. So the number of numbers to skip must be multiplied by the length of the number (4 or 8).
The [rb] operation allows you to read file bytes as integers in the range from -128 to 127. In this case, the [le] (length) parameter is used, which determines the number of bytes to skip in the file before reading. That is, the actual reading occurs not from the first byte, but from the byte whose number is [le]+1. If the reading occurs in a text array, then 1104 is added to the negative values, which converts Russian ASCII codes in Windows format to Russian Unicodes. This allows you to read Russian books in Windows text format, which is used in the book reader. When writing with the [wb] operation, the valuesof the array elements are converted to bytes. In this case, the Russian Unicodes of the t() array are converted to negative valuesby subtracting 1104. The file is written from the beginning and re-created. These operations allow you to manipulate the contents of the file in any way. But you should remember that there are many bytes in the file, and ACL is not a fast language. Therefore, it is reasonable to manipulate only relatively short files.
But working with files is not limited to writing and reading data. There are many other necessary and useful operations. For this reason, a special command has been created in ACL, which is called #file, or #f for short. This command has many operations, and the operations are combined into one command only because they all work with files. In fact, some operations are entire programs with their own parameters and arguments, and there is no connection between the operations. The minimum number of characters in the name of an operation is 4, otherwise it is difficult to separate all the names without losing the meaning.
We will begin the description of operations according to the principle from simple to complex. The first operations are those that the operating system usually performs. Where not specifically indicated, file names are counted from the "working" folder. So
#f [op=fold; file=any;]
This operation resets the "working" folder, the name of which is specified by the [file] parameter relative to the interpreter folder. The [/] symbol can be used in the name for nested folders. After executing this command, the address of the "working" folder changes for the entire work of the interpreter, i.e. even after the program has finished. The only way to redefine the "working" folder is to execute this command again with a new value for the [file] parameter.
#f [op=size; file=any;]
This operation determines the size of the file whose name is specified by the [file] parameter. The size is returned in s(1). If s(1)=0, the file does not exist.
#f [op=dele; file=any;]
This operation destroys the file on disk whose name is specified by the [file] parameter.
#f [op=copy; n=; file=newtotal;] file1.ext\E file2.ext\E . . .
This command creates a new file with the name specified by the [file] parameter and with contents that are the concatenated contents of a series of files whose names are specified by a series of FT (formatted text) arguments. The FT is described above in Section 3. In other words, this operation copies several files into one. The number of files to be copied is specified by the [n] parameter. The number of arguments may be greater, but cannot be less, or an error is logged.
#f [op=divi; file=; form=; b=; le=; n=; xsh=;]
This operation, on the contrary, allows you to split a file into parts and write one part to a new file. The name of the original file is determined by the [file] parameter, the name of the new file is determined by the [form] (formed) parameter. The original file is treated as a matrix of bytes, from which a submatrix isextracted. To perform this work, 4 parameters are required. The [b] (begin) parameter determines the number of bytes that are skipped from the very beginning. After that, some bytes of length [le] (length) are written and then bytes of length [xsh] (xshift) are skipped again. Such le-xsh operations are repeated [n] (number) times. The new file will have exactly [le]*[n] bytes. This operation is useful, for example, for selecting a small part of a large picture into a new picture. It can also be useful when working with numeric matrices.
#f [op=fcat; file=any;]
This operation returns a directory of files in the folder specified by the [file] parameter. The folder name must be specified completely, starting from the interpreter folder. The directory is written to the text array t() starting at the index specified by the s(3) parameter. After writing, as usual, s(4) and s(5) indicate the start and length of the written output. If the [file] parameter does not point to a folder, s(5)=0 is returned. The list is specified as a single line, with file names separated by the pipe character [|].
#f [op=find; b=; le=; file=any;]
This operation searches for a certain set of bytes within the file whose name is specified by the [file] parameter. The sequence of bytes must be previously determined by their valuesin the entire array i(), with the index of the first element being determined by the [b] (begin) parameter and the number of bytes being determined by the [le] (length) parameter. The result of the search is returned in the s(2) parameter as the number of repetitions of the given byte system. It is important to remember that bytes have valuesfrom -128 to 127, unlike ASCII codes. For example, the code
#d 2 i(11) 13 10 #f [op=find; b=11; le=2; file=any;]
will show the number of lines inside the file in DOS and Windows systems as the value s(2). If s(2)=0, then the file either has one line, or it is written in the UNIX-oid system, or it is numeric.
#f [op=repl; b=; le=; mo=; file=any;]
This operation does a more complicated job compared to the previous operation. It finds all copies of one byte system and replaces them with another byte system. Again, all bytes equal to the value of the [le] parameter must be specified in the i() array, starting from the index specified by the [b] parameter. But among them, the [mo] first bytes determine the system that is replaced (modified), and the remaining [le]-[mo] bytes determine the system that will be written instead. The new content will be saved in a file with the same name. Therefore, if the original file needs to be saved, it must first be copied with a different name. For example, the code
#d 2 i(11) 44 46 #f [op=repl; beg=11; len=2; mod=1; file=some.dat;]
will replace all commas in the file with periods.
#f[op=line; file=any; n=; b=; le=; emp=;]
This operation reads and writes lines of text to a file. If the parameter [n=-N;] is negative, then the N-th line of text in the file is read and its content is written to the text array t() starting from the index specified by s(3). After the operation, s(4) and s(5), as usual, show the beginning and size of the written text. If there is no N-th line in the file, then the parameter s(5) will be equal to zero. Conversely, if the parameter [n=N;] is positive, then the N-th line is written to the file, the content of which will be a part of the text array t(), starting from the first element whose index is determined by the parameter [b] (begin), and the number of characters is equal to the value of the parameter [le] (length). If the file had more than N lines, the old content of the N-th line will be changed. If the file had less than N lines, it will have exactly N lines. The lines between the last of the former and the N-th will be empty. This mode of operation corresponds to old versions, when the parameter [emp=0;]. But if the parameter [emp] is not equal to zero, for example, [emp=1;], then with a positive [n=N;] the N-th line in the file is simply deleted. The parameter [emp] (enhanced mode parameter) allows implementing additional modes of command operation, but it is absent in old versions, which correspond to the zero value. Therefore, do not forget to return the parameter [emp] to its original state [emp=0;].
#f [op=list; file=any; c=; b=;]
This operation does a special job. It reads the file whose name is specified by the [file] parameter and creates a special string of text in the text array t(). It takes all the characters from the beginning of the file up to the character whose ASCII code is specified by the [c] (code) parameter, including itself. Then it skips all the characters after the [c] ASCII code until it encounters the character with the ASCII code [b] (begin), including itself (that is, it skips that too). Then it takes all the characters again up to the first occurrence of the [c] ASCII code, and so on. It looks as if the command takes one part of two parts of the records in the file. If the record has a name and a body, the command can make a list of names. The number of names is returned in the s(2) parameter, and the formed string is written to the text array t() starting at the index specified, as usual, by the s(3) parameter. After the operation, the number of the first written character and the number of characters can be obtained from the parameters s(4) and s(5), similar to other similar operations. In principle, such work can be done using other ACL commands, but this operation works much faster, especially for large files. Each programmer decides for himself how to use this operation in a real program.
The operations described below implement much more complex work, but this work is done completely automatically, so it is easy to use the operations. And all the features of the subsequent work of the program can be studied experimentally, but already in the process of working with the finished program.
#f [op=edit; c=; mo=; file=; b=; le;]FT
This operation starts a ready-made text editor for editing the contents of a file in a separate window. The file name, as usual, is determined by the [file] parameter. If the file does not exist, it will be created. In this case, the editor starts with empty text. The edited content will be written to the same file if [mo=1;] or will not be written at all if [mo=0;]. The second mode is convenient for information files, the content of which should only be shown and corrections are undesirable. With [mo=1;] the file is overwritten automatically when exiting the editor. The editor menu has three buttons: [find] [font] [exit]. The [find] button is standard. The [font] button allows you to select one of 5 logical fonts and the font size. These valuesare stored in the [fk] == s(27) (font kind) and [fs] == s(28) (font size) parameters. As usual, the changed valuesof the parameters will be valid until the next definition, and they can be changed anywhere in the program. The current valuesof these parameters are stored in the file "start.acl". Logical fonts are actually absent. The interpreter checks for fonts on the computer and finds real fonts that are close in properties to the declared logical fonts. So the fonts can simply be checked empirically and the appropriate one selected. The [c] parameter is taken into account similarly to other GUI operations. Namely, if [c] = 0, the program continues executing other commands after opening the editor window. Previously, this was used for automatic presentation using the #robot command. Now the #robot command is blocked, but the mode is saved, but it should be used with caution. If [c] = 1, the program waits for the user to close the window. The cursor position when entering the editor is determined by the s(1) parameter without a name. After exiting the editor, the same parameter contains the cursor position before exiting. The position is specified by the character number in the text starting from the beginning. The first character has index 0. Knowing the cursor position can be used, for example, when reading books, since it allows you to remember where you stopped reading and start right from that place next time. The window title is the full file name. There is a special mode of operation of the command, which corresponds to [file=here;]. In this case, the editor works with a part of the text array t() instead of the file. This part starts with the index determined by the parameter [b] and has [le] characters. In this case, the parameter [mo] must have the values-1 or -2. With [mo=-1;] the editing result is not written (read only), and with [mo=-2;] the text edited by the editor is written again to the text array, starting from the index determined by the parameter s(3). As usual, after writing, the parameters s(4) and s(5) show the beginning and length of the written text. In this case, the window title is specified by the argument in the form of formatted text. The argument is mandatory and its absence is recorded as an error. In new versions of the interpreter, the editor has additional menu sections and a built-in description (Help).
#f[op=html; file=any;]
This operation enables the programmer to display html files, i.e. launch a simple browser. The file name is defined by the [file] parameter, but in this case the name must be specified fully relative to the interpreter folder; the working folder is not used. Hyperlinks inside the file are shown in a separate window, which is superimposed on the previous one, so in order to go back, you just need to close the current window or move the new window to another location. The window sizes in this and the previous operations are set in a standard way, but the user can change them to his taste with the mouse (moving the borders). The browser is implemented in the simplest version and does not contain any menus or icons. It is intended mainly for displaying specially prepared information texts, all navigation in which can be organized using hyperlinks.
#f [op=choo; mo=; file=;]
This operation starts a special program called FileChooser in Java. FileChooser enables the user to view the full file structure of the computer being used, similar to the File Manager in Solaris OS or the My Computer program in Windows OS. Viewing begins with the folder specified by the [file] parameter. The [file] parameter can point either to any file counted from the main interpreter folder or directly to the folder. To specify the main folder, that is, the interpreter folder, you can use [file=start.acl;]. The program has two variants. If [mo=0;], then the general form is used and all files are shown. The [Select] button allows you to select a file. The full name of the selected file, counted from the interpreter folder, will be written to the t() text array, starting with the element according to the value of the s(3) parameter. After the operation, as usual, s(4) and s(5) show the beginning and length of the record. The user, in principle, has the ability to select a file located outside the interpreter folder. But in this case the operation will return an empty name and the parameter s(5)=0. In any case the programmer should be careful and check the existence of the selected file using the operation [op=size;] in addition to checking the value of s(5) before performing any operation on the selected file. If [mo=1;], then a special form is used in which only graphic files with a preview are shown. After selecting a file, its name will be transmitted in the same way as described above. The programmer can use the chosen name at his own discretion.
The following operations belong to the file command because they actually create files. But these files are of a special nature. These operations can be useful only in image processing programs. Therefore, readers who are not interested in this topic can skip studying these operations. Moreover, special information about images is used here. In addition, these operations are implemented only on PCs, they are not available on PDAs. As a rule, these operations are used in a block with other commands. After this introduction, let's get to work.
#f [op=tobm; file=; form=; dir=; n=; col=;]
This operation converts graphic files with extensions (gif, jpg, png) into byte-map files. Each byte of such a file describes a gray level from 0 to 255. The [file] parameter must specify the name of the graphic file, for example, [file=one.jpg;]. However, if [file=here;], the image will be read not from the file, but from the RAM, which stores the image array, as an element with the number [n]. Such an image must be previously recorded. As a result of the operation, a new file with the name specified by the [form] parameter will be created as a graphic file in a new format. This format is non-standard, some call it raw. In this case, the [dir] (direction) parameter determines the vertical writing direction. If [dir=1;], the writing goes from top to bottom, which is typical for graphic files. For any other value, for example [dir=0;], the image is written starting from the bottom line up, as is done in all calculated images. As usual, the elements of the image lines are written in a row. The width of the image is returned to the parameter s(12), and the height to the parameter s(13). Colored images are converted to gray by the law of the scalar product with a given color, the number of which in the color array is specified by the parameter [col]. Let this color have components R, G, B. Then the color of each pixel leads to a gray level g by the law g = (r * R + g * G + b * B) / 255), but within the interval (0.255). This method allows you to use color filters when converting an image, as well as change its brightness. Information about colors will be described below in the section on graphics description. The size of the recorded file in bytes is equal to the number of pixels in the image.
#f [op=tocm; file=; form=; dir=; n=;]
This operation converts graphic files with extensions (gif, jpg, png) into color-map files. Every three bytes of such a file describe the level of red, green and blue from 0 to 255 for one point of the image (pixel). The [file] parameter specifies the name of the graphic file, for example, [file=one.jpg;]. However, if [file=here;], the picture will be read from the RAM from the image array as an element with the number [n]. Such a picture must be previously recorded. As a result, a new file with the name specified by the [form] parameter will be created as a graphic file in the new format. In this case, the [dir] parameter determines the vertical writing direction. If [dir=1;], the writing goes from top to bottom, usual for graphic files. For any other value, for example [dir=0;], the picture is written starting from the bottom line up, as is done in all calculated images. As usual, the elements of the picture lines are written in a row, three colors for each element. The width of the image is returned in the parameter s(12), and the height in the parameter s(13). The size of the written file in bytes is equal to three times the number of pixels in the image.
#f [op=tops; mo=; uni=; file=; form=; n=;]
This operation converts graphic files with extensions (gif, jpg, png) to EPS files (encapsulated postscript file). The [file] parameter must specify the name of the graphic file, for example, [file=one.jpg;]. However, if [file=here;], the picture will be read from the RAM from the image array as an element with the number [n]. Such a picture must be previously recorded. As a result of the operation, a new file with the name specified by the [form] parameter will be created as a graphic file in the eps format. The file name is specified together with the extension. It does not have to have the eps extension. In this case, the [mo] parameter must be 0 or 1. The value 0 leads to the creation of a black-and-white eps file, and the value 1 leads to the creation of a color eps file. Other valueslead to an error. The [uni] parameter additionally defines a scaling factor for the picture to match the dimensions of the eps picture on the screen to the original picture. This factor is equal to the ratio of the screen pixel to the PS point in units of 0.0001. For example, my DELL Latitude laptop has 1024 pixels with a screen size of 28.42 cm. When I use GhostView in zoom mode, showing A4 paper (595 pixels) at 26.4 cm, the ratio will be 0.6255. With this value, GhostView on my computer shows the image exactly as vkACL does. However, this ratio may be different on other computers. Each user can determine the ratio empirically. In my case [uni=6255;]. Sometimes it is very important to have each pixel correspond to each screen point, since interpolation leads to artifacts. It is appropriate to note here that the full version of the interpreter executes the #pd command, which allows you to convert a wide range of graphic formats to pdf format. This is done by a special library of Java classes written by other authors. And I implemented this operation myself.
#f [op=topng; form=; n=;]
This operation converts graphic images previously saved in the computer's memory into a png file. Images are written into the computer's memory using the graphic commands #w #g #eg . These commands themselves are capable of converting images into a jpg file. But the jpg format is not always suitable for line graphics. The files are unreasonably large, and the lines are surrounded by a noticeable dirty background caused by the jpeg compression algorithm. In this case, it is reasonable to save the created images into memory and then convert them into a png file using the specified operation. Here, the [form] parameter specifies the name of the file without the extension that will be written. The extension is always ".png". The [n] parameter specifies the number of the image previously saved in memory. If the image does not exist, an error message will be displayed. This operation is made for universality. Since images are created by several commands, the implementation of writing to files of different formats in each command leads to an increase in code and a complex structure of parameters.
.
8. COMMUNICATION WITH THE USER
Any program must receive data from the user in order to work. This data is usually divided into two types. The first type of data is conventionally called tables. This is, as a rule, a system of numbers, words, pictures, which has a certain structure, sometimes quite complex, and is written in files. The second type of data is conventionally called instructions. These are instructions to the program on what calculations to perform, what tables to write and what to do with the existing tables. In the first programming languageswritten for computers without a screen, instructions were also written to a file, either in the program itself or in special text files. This method is still used today and is sometimes even quite convenient. For example, one program can generate tables and instructions for another program that runs immediately after it. The second program reads the instructions, transforms the tables and in the same way transfers the entire arsenal to the third program. In this case, the user participates only at the very beginning, after which the programs communicate with each other automatically.
But there are other programs that are completely dependent on the user and request data from him. For example, a program that collects a database for selecting acquaintances between young men and women. Such programs usually implement an interactive mode in which the user is told something, asked to make a choice or enter information in prepared forms. Therefore, programs running in window operating systems have a certain arsenal of tools for convenient graphical communication with the user. In low-level languages, it is possible to create tools of this type yourself, although this is quite cumbersome work. As for ACL, it does not have many such tools yet, but over time there will be more. Nevertheless, the most necessary tools are still there. We will discuss them in this section. The first command of this type has already been discussed in Section 3. This is #m (message). It displays formatted texts with certain information and sometimes asks the user to make a choice by clicking on certain buttons. The operations of communication with the user also include the edit, html and choo operations of the #f (file) command. The first of them asks you to type text in the editor, the second shows information in the form of formatted HTML text with links, and the third asks you to select a file, simultaneously showing what files are on the computer. In this section, we will consider two more commands of this type. The first command is #select or
#sel [nx=; ny=; mo=; wid=; hei=; tsi=; col=; emp=; xsh=; ysh=;] FT FT.
This command creates a new panel showing a square table of buttons. The number of buttons in one row is specified by the [nx] parameter, and the number of rows is specified by the [ny] parameter. The command offers the user to make a choice of one option from many options. The panel has a title, which is determined by the first argument FT. The second argument FT contains the names of all the buttons. The names inside FT are separated by the vertical bar [|] character. The names of the buttons first fill the first row, then the second, etc. There are several modifications of the program's operation. If [mo=1;], the buttons are specified by pictures from files with the jpg extension, which are searched for in the current folder. Do not forget to correctly determine the current folder before using the command. In this case, the names of the buttons are the file names, but without the extension. For example, "run" means the file "run.jpg" in the current folder. If [mo=0;], the names of all the buttons are texts that are shown inside a rectangle of a certain size, painted in a certain color. In this case, defining the [col=j;] parameter means that j is equal to the index of the color array element, which specifies the text color number (255 by default), the next element of this array specifies the background color (rectangle). The color array can be redefined with the #color command. The [wid] and [hei] parameters define the size of the rectangle in screen pixels. The [tsi] parameter specifies the text size. When the user clicks one of the buttons, the panel disappears and the [&] variable becomes equal to the number of the selected button. The programmer can use this information at his own discretion. As a rule, this command is followed by a series of conditional commands #case .... #end | , which processes each value of the [&] variable from the desired range.
Previously, the button table was installed automatically in the middle of the screen. Then a new [emp] (enhanced mode parameter) parameter was introduced, the default value of which is always zero. In this case, the old mode is in effect for compatibility with previously written programs. If its value is different from zero, then the position of the button table is determined by the [xsh] and [ysh] parameters, namely, they set the offset of the upper left corner of the button panel from the upper left corner of the screen. When changing the [emp] parameter, do not forget to zero it after executing the command.
Here it is useful to inform in advance that a more complex mode can be used to implement such a request. The #w (window) command allows you to display an image of arbitrary content on the screen in the form of a single button. When the user clicks on the image, the program returns the cursor position at the time of the click. The image can depict a series of buttons in an arbitrary configuration, for example, in the form of the periodic table, and the number of the pressed button can be determined by the cursor position. But this mode requires writing complex code on ACL, while the #sel command does everything automatically.
The second useful command is #inp (input) which creates a new panel that contains input boxes with comments in a specific order.
#inp[n=; le=; mo=;] FT FT FT ...
Each input window allows entering one line of text. The number of lines is determined by the parameter [n]. The simplest case is [n=1;] with one input window. In this case, the panel has a title determined by the first argument of FT. The comment for the window is specified by the second argument of FT. Finally, the third argument of FT contains the initial text that will be entered into this input window. But if [n] > 1, then two modifications of specifying comments and texts are possible. If [mo] is an even number (0,2,...), then the 2nd argument of FT specifies the first comment, the 3rd argument of FT specifies the first text, the 4th argument of FT specifies the second comment, the 5th argument of FT specifies the second text, and so on. So in this case, each argument of FT specifies one comment or text. In the opposite case, if [mo] is an odd number (1,3,...), then the 2nd argument of FT defines all comments separated from each other by the vertical bar [|], and the 3rd argument of FT defines all texts separated in the same way.
There are also some modifications of the placement of comments and input boxes on the panel. If [mo] = 0,1, then each comment and each input box are placed on a new line from top to bottom. In this case, the comment is placed above the input box. If [mo] = 2,3,4,5, then each comment+text pair will be placed on one line, forming one column. If [mo] = 6,7, then the comment+text pairs will be placed in two columns. In this case, the [n] parameter must have an even value and the first half of the input boxes will be in the first column, and the second -- in the second. If [mo] = 8,9, then the comment+text pairs will be placed in three columns. In this case, the [n] parameter should be divisible by three, and the first third of the input boxes will go to the first column, the second to the second, and the third to the third. If [mo] > 9, the input boxes will be placed 4.5,.. per row, but the columns are not aligned. I have never used the latter mode.
The bottom line of the panel contains two buttons [OK] and [Cancel]. The [le] parameter defines the length of the empty space on both sides of these buttons. This allows you to set the length of the input boxes, since comments are written entirely, and the input boxes have no size and their length depends on the overall width of the panel, determined by other parameters. In particular, if [mo=0;] or [mo=1;], the panel width depends on the maximum length of the specified lines. Any width can be formed using the [le] parameter. Usually [le] = 50, but it can be more or less. The [le] value is optimized empirically. The panel is always placed in the center of the screen.
The contents of all input boxes can be changed by the user. After exiting the dialog, new texts will be placed in the text array t() similar to the #print command. The contents of different input boxes are separated by ASCII code 10 (line separator). Let me remind you that the index of the first element to write to the character array t() is determined by the s(3) parameter. After the operation, the s(4) parameter points to the initial index of the first element of the record in t() with the new text (s(3) will be different) and s(5) will show the length of all records including code 10 after each line. Therefore, be careful when working with the entered text. For example, in the case of [n=1;] its length will be s(5)-1.
The panel contains two buttons [OK] and [Cancel]. If the user selects the [Cancel] button, the text array t() will not be filled, and the [&] variable will be equal to 2. The text array will be written only if the [OK] button is pressed. In this case, [&] will be equal to 1. The location of the buttons also depends on the modification. If [mo] = 0.1 or > 5, then they are located in the center and [le] specifies empty space on both sides. If [mo] = 2.3, then they are located on the left side, and all empty space of length 2*[le] is on the right. If [mod] = 4.5, then they are located on the right side, and all empty space of length 2*[le] is on the left.
.
9. WHAT ELSE IS THERE
There is a special command for working with zip archives, there is a command for simple graphics, as well as commands that allow you to show ready-made graphic modules. There is also an additional command for advanced graphics, which provides almost all the possibilities for drawing an arbitrary picture and processing images obtained, for example, by a digital camera. There is also a command for recording and playing sound, there is a command for animation, that is, showing pictures with automatic frame change in any shape. There is a #system command for running external ready-made programs and other system operations. Of great importance is the mathematics command, which has many operations and allows various mathematical procedures to be performed on matrices and arrays of large numbers directly in the computer code and therefore quickly. There is a command for operations with the text array t().
Finally, the apparatus for creating and working with supercommands has been implemented. A supercommand is a ready procedure that is written to a file (it is possible with a preliminary instruction) and that can read arguments from parameters or from the text array t(). This file is placed in a special folder called [proc]. After that, the corresponding procedure from the file can be called by the file name (without the extension) by putting two signs [##] before the name. The convenience of this approach is that a once defined procedure can be used many times in different ACL programs, and its call is similar to running a regular command.
All the language features are described in detail in a more complete description in Russian. Translation into English is now easy on Google and Yandex. There are articles on each command separately and an article on some programming methods. Recently I made a special version of the interpreter that works with ready-made ACL files like a regular player. It has a number of advantages. Firstly, the corresponding jar file can be renamed to any name. Secondly, the program shell, in particular the main window menu, can be configured using a special protocol. Well, the size of this program is much smaller, since it does not contain debugging tools, in particular built-in language descriptions and various demonstrations.
Obviously, the language can be expanded infinitely. I used much of what Java gives in ready-made form and what I have developed throughout my life. You can also add mathematical procedures and interface creation procedures. There is no command for working with media files yet, although this is also possible. There is another channel for development - accumulating a bank of ready-made programs in the ACL language. The thing is that there are already many ACL programs that can be used effectively without knowing the ACL language at all, and these programs are built into the shell. In particular, there is a very advanced calculator with 8 memory cells that allows you to calculate using formulas and remember many variations of already filled formulas for repeated calculations. There is a #pd command that implements the ability to create and work with pdf files. This is very complex work and for its implementation I used a Java class library called "iText", which is offered for free on the Internet. I am convinced that the program is worth learning the ACL language and using it in your work. I myself use it every day to do many jobs and it helps me a lot.
For those curious, I will show the text of the calculator program here.
----------------------------------------------------
#pro main #f [op=fold; file=0;] # &=1; !
#case 1 # s(3)=1; #pr 01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|\E
. #sel [nx=9; ny=3; mo=0; wid=30; hei=25; tsi=16; col=255;] Select variant\E \T1 s(5)\E # S=&; &=S<2; !
. #case 1 #p [file=calcul.inf;] #f [op=edit; mo=1; c=1;] # Q=3; #end |
. #case 2 # a=0; b=0; c=0; d=0; e=0; f=0; g=0; h=0; #e _inpc # &=Q; !
. . #case 1 #m [op=uni;] Would you like to continue ?\E Continue|This|Other|No\E # Q=&+1; !
. . #end | # &=Q; !
. #end # &=Q-2; !
#end #f [op=fold; file=oldf;]
@
#pro inpc # &=(S-1)<1; !
#case 1 # s(3)=1; #f [op=line; n=-S+1; file=calcul.txt;] #p [err=1;] #%
. #case 10101 #m [op=win;] \n\U32*5;Sorry, you have typed\n\U32*5;the invalid expssion.\n\U32*5;Please try again.\n\E #end |
. # s(3)=1; #inp [n=8; le=80; mo=3; ysh=70;] Calculator\E a = |b = |c = |d = |e = |f = |g = |h = \E \T1 s(5)\E # Q=&; !
. #case 2 # Q=Q+1; s(26)=0; #end | # &=Q; !
. #case 1 # z=s(5); s(3)=3999; #te [op=repl; b=1; le=z; c=10; mo=124;]
. . #e _make #e _text #p [err=0;] #f [op=line; n=S-1; b=1; le=z;]
. . #m [op=win;] \na =\G a;\nb =\G b;\nc =\G c;\nd =\G d;\ne =\G e;\nf =\G f; \ng =\G g;\nh =\G h;\n\E
. #end |
#end |
@
#pro make #te [op=find;b=1;le=z; n=1; cod=124;]
# A=1; B=i(1)-A; C=i(1)+1; D=i(2)-C; E=i(2)+1; F=i(3)-E; G=i(3)+1; H=i(4)-G; I=i(4)+1; J=i(5)-I; !
# K=i(5)+1; L=i(6)-K; M=i(6)+1; N=i(7)-M; O=i(7)+1; P=i(8)-O; !
#pr \#\U32;a=\TA B ; b=\TC D ; c=\TE F ; d=\TG H ; e=\TI J ; f=\ TK L ; g=\TM N ; h=\TO P ; \#p\U32;\[\]\U32; \E
#p [b=s(4); le=s(5);]
@
# e _main !
------------------------------------------------ ------
This program uses much of what is written above. It uses a working folder named 0. At first, the program shows a table of buttons of size 9*3 with the names of calculation options. The number [01] is special, when selected, a text editor for editing a file named "calcul.inf" in the working folder, which contains instructions for the user and a reminder of the options. When selecting other numbers, the procedure for entering formulas with control of possible errors is launched. For this, the [err] parameter and the #% command are used . The entered formulas are written to a text array and are dynamically executed as a procedure. If an error is detected, the program returns to formula input. If there are no errors, th
.