My Error

After I uploaded the version of Infiqs dated 13 September 2007, I found a bug in it which can cause wrong numerical answers with no warning from javac or java. (Infiqs was deleting parentheses that it had no business to delete. I am speaking of parentheses around boolean expressions, on dec lines.) If you are using that 13 September 2007 version, please download this new version. If you extended the grammar table by adding lines for new artificial left parens, your new grammar lines will need to be changed, to agree with my lines for artificial left parens in this new version. Whether you extended the grammar table or not, please re-expand your .infiqs files to .java files, and then compile all those .java files to .class files. (Again, I mean those .infiqs files with dec lines having parentheses around boolean expressions.) Also, please tell all your friends and acquaintances who are using Infiqs.

Abstract

The Infiqs freeware macro-expander is an old style table driven operator precedence compiler for assignment statements. It is meant to help programmers writing Java programs that use the BigDecimal class. It allows them to use infix operators for the arithmetic of BigDecimal. Infiqs is written in Java. The length of the Infiqs.java file is a little over ten thousand bytes.

Download

This file, index.htm, serves as a readme file for Infiqs. To get a zip file containing the java source for Infiqs, and infiqs sources for some other files, and a copy of this file which you are reading, click for infiqs.zip.

Opportunity and motivation

In the fall of 2004 the Sun company brought out a wonderful new version of their Java™ language. It is version 1.5, or just Java 5 for short. One of the many big improvements to the language is the addition of features to the BigDecimal class. BigDecimal numbers now operate like floating-point numbers, but the precision is arbitrary and the exponents can go up very high. Java does not cost us users any money, and there are places in numerical analysis where these numbers are exactly what is desired. There is just one little problem. The arithmetic of the BigDecimal class does not use the plus and minus and asterisk and slash signs. The method calls have to be written out in dot notation. As is well known, programmers are not permitted to overload operators in the Java language, so one must write things like

x = x.subtract((x.pow(3,mc).subtract(new BigDecimal("17",mc),mc)).divide((new BigDecimal("3",mc).multiply(x.pow(2,mc),mc).subtract(new BigDecimal("0",mc),mc)),mc),mc) ;

Macro-expansion

Can the reader guess what I meant when I wrote that long line? That was a trick question. I never wrote that. I used a macro-expander called Infiqs to write it. What I wrote was

dec x = x - ( x ^ 3 - "17" ) / ( "3" * x ^ 2 - "0" ) ;

which can actually be read by a human. It is recognized as part of a Newton-Raphson loop to take the cube root of 17. The dec at the left of the line is the signal to Infiqs to expand the rest of the line. The quote marks go around BigDecimal constants. The ^ sign is borrowed from the Basic language to mean taking a power. (This is in disagreement with the meaning of ^ in Java, so I have also made the ** digram mean power, as in Fortran.) Blanks are used heavily to separate the tokens. An example is the file Junk.infiqs. I gave that file to Infiqs by doing

java Infiqs < Junk.infiqs > Junk.java
at the dos prompt, and Infiqs wrote for me a file called Junk.java. I compiled and ran that Java program, using Java 5 of course, and it printed
6.333333333333333333333333333333333333333
4.363496460449369036626654355186211141889
3.206615103537771850970414256164688786719
2.688847955387110922672126110499621766105
2.576347106780403320815289088011395921633
2.571291543756804435282910953080707400544
2.571281590696762314228170393785262496342
2.571281590658235355453764479839792453229
2.571281590658235355453187208739726116428
2.571281590658235355453187208739726116428

Grammar

So what is Infiqs? In the first place, it is an intentional misspelling of the word infix, to make it easy to find with a search engine. In the second place, Infiqs is an old style operator precedence compiler for assignment statements, using a table. Here is the table:

static Inf[] grammar=
{
new Inf(  0,  "..name..",            "",           "", 900, 'X' ),
new Inf(  2,        "**",       ".pow(",       ",mc)", 100, 'R' ),
new Inf(  2,         "^",       ".pow(",       ",mc)", 100, 'R' ),
new Inf(  2,         "*",  ".multiply(",       ",mc)",  90, 'L' ),
new Inf(  2,         "/",    ".divide(",       ",mc)",  90, 'L' ),
new Inf(  2,         "+",       ".add(",       ",mc)",  80, 'L' ),
new Inf(  2,         "-",  ".subtract(",       ",mc)",  80, 'L' ),
new Inf(  2, "compareTo", ".compareTo(",          ")",  80, 'L' ),
new Inf(  2,       "min",       ".min(",          ")",  70, 'L' ),
new Inf(  2,       "max",       ".max(",          ")",  60, 'L' ),
new Inf(  2,        ">=", ".compareTo(",       ")>=0",  50, 'L' ),
new Inf(  2,         ">", ".compareTo(",        ")>0",  50, 'L' ),
new Inf(  2,        "<=", ".compareTo(",       ")<=0",  50, 'L' ),
new Inf(  2,         "<", ".compareTo(",        ")<0",  50, 'L' ),
new Inf(  2,        "==", ".compareTo(",       ")==0",  40, 'L' ),
new Inf(  2,        "!=", ".compareTo(",       ")!=0",  40, 'L' ),
new Inf(  2,        "^^",         " ^ ",           "",  37, 'L' ),
new Inf(  2,        "&&",        " && ",           "",  33, 'L' ),
new Inf(  2,        "||",        " || ",           "",  30, 'L' ),
new Inf(  2,         "?",         " ? ",           "",  25, 'L' ),
new Inf(  2,         ":",         " : ",           "",  25, 'L' ),
new Inf(  2,         "=",         " = ",           "",  20, 'R' ),
new Inf(  2,         ";",         " ; ",           "",  10, 'L' ),
new Inf( -1,        "-(",            "",  ".negate()",   0, 'X' ),
new Inf( -1,   "negate(",            "",  ".negate()",   0, 'X' ),
new Inf( -1,      "abs(",            "",     ".abs()",   0, 'X' ),
new Inf( -1,   "signum(",            "",  ".signum()",   0, 'X' ),
new Inf( -1,         "(",           "(",          ")",   0, 'X' ),
new Inf( -2,         ")",            "",           "",   0, 'X' )
};

The left-most column is the arity, where left-paren is given an artificial arity of -1 and right-paren is given -2. The next column is the operatorName of the token. After that come the leftPart and rightPart of the operator when macro-expanded. Next to last is the precedence. The last is the associativity, 'L' for left or 'R' for right or 'X' for irrelevant. The zero-ary operator ..name.. is mostly just a place-holder. Tokens not found in the table are given the same object as ..name.. . That is, all zero-ary tokens are treated alike.

The ternary operator

The reader may have noticed that at least five of the operators in the table have no special connection to BigDecimal arithmetic. They are
 ^^     &&     ||     ?     :
The ? and : are parts of the ternary operator. The && and || are the familiar “conditional and” and “conditional or” of Java. The ^^ is used instead of ^, because ^ means power in Infiqs. That is, ^^ is my XOR operator. I cannot think how to put a singulary ! operator into Infiqs, but the ^^ may provide a work-around.

For an example of a ternary operator, I respectfully suggest that the reader click on UseTernary.infiqs and on UseTernary.java. Actually, Infiqs does not know that the question mark and the colon work together, or that there must be exactly one of each, or that they must be in order. However, javac knows.

How Infiqs works

The action of Infiqs is as follows: First a line is read from the system input stream. Then the line is broken on white-space to tokens. If there are no tokens or if the left-most token is not dec then the line is merely copied to the system output stream. Otherwise Infiqs looks to make sure the rightmost token is a semicolon. If it is, then the dec on the left is replaced by a left paren and the semicolon on the right is replaced by a right paren. Then the tokens are looked up in the table to find their operators. Any token not found in the table is assumed to be zero-ary and is given the operator for ..name.. . A zero-ary beginning with a " mark is assumed to be a BigDecimal number constant, so it is given a constructor. Then the parentheses are checked for nesting and balance. Artificial tokens like -( and abs( are treated like left parens here. Then the arities of neighboring operators are used to check for good grammar. For example, a left paren cannot be followed by a binary operator.

The program on the line is now known to be grammatically correct, as far as Infiqs is concerned. The next thing is to pick up the white space on the left of the dec token. This is saved for later.

Now comes the actual macro-expansion. The tokens are looked at from left to right. Zero-aries float up to the upper array. Left parens, including artificial things like -( and abs(, fall down into the lower array. A binary operator forces higher-precedence binary operators from the lower array to the upper. A binary operator with left associativity also forces binary operators having the same precedence. Then the binary operator falls down into the lower array. A right paren forces non-paren operators from the lower array to the upper until it finds its corresponding left paren (or artificial left paren,) and they go to their places in the upper array.

When all the operators have been processed, the upper array consists of exactly one string. A semicolon is appended to the right of the string and the saved white-space is appended to the left of the string, and the string is outputted to the system output stream.

When all the lines of the input stream have been processed, the macro-expansion is finished.

Taking advantage

It is easy and useful to take advantage of Infiqs’s simplicity. For example, a line like

dec a[j] = b[j+2] + c[2*j-3] ;

will be macro-expanded correctly. That is, the tokens a[j] and b[j+2] and c[2*j-3] will look like zero-aries, because there is no white-space in them. Infiqs will never notice that they are subscripted. (Of course, javac will notice the subscripts.) In other words, subscripts cost nothing at macro-expansion time, and the grammar table does not have to have any information about them. That same simplicity permits us to write

dec y = x + SinD.sin(z,mc) ;

where sin is a static method of the SinD class. (I include SinD.infiqs in the zip file.) Again the trick depends upon SinD.sin(z,mc)’s looking like a zero-ary. This means that we cannot put actual BigDecimal arithmetic inside a static method call. Rather, we must use a temporary variable on a previous line:

dec temp = p + q ^ 2 ;
dec y = x + SinD.sin(temp,mc) ;

or on the same line

dec temp = p + q ^ 2 ; y = x + SinD.sin(temp,mc) ;

or the like. It goes without saying that all the variables have to be declared by the programmer. Infiqs has no way of knowing how to declare variables. Neither can it tell how the programmer has declared them. For an example of taking advantage, please click on SubscriptsDemo.infiqs and on SubscriptsDemo.java.

License

I have made the Infiqs program as simple as I know how, so that any programmer can make changes to it to suit the application. Perhaps Infiqs may be useful for other things besides BigDecimal, such as BigInteger, vectors, matrices, rationals, complexes, Apfloat, interval arithmetic, or finite local Taylor series. Everybody may use my software for any purpose and make any desired changes, because my software is all in the public domain. (But Java™ is the property of Sun, of course.)

Warning

The files in the zip archive which have the .infiqs suffix are just things I wrote to test Infiqs.java, and they themselves are not adequately tested. Beware.

E-mail and links

All constructive and destructive comments come to me, Harold Kaplan,

       at        dot
smtw2gh  toadmail   com
The date of this revision of Infiqs is 17 September 2007.

For links to Harold Kaplan’s other programs, click on programming.htm

For many more links for languages connected with Java, click on http://www.robert-tolksdorf.de/vmlanguages.html.

To top