Table of Contents


Introduction
Download and install
SlideRule, a pseudo slide rule
Calculator, an incomplete calculator
Stat, a macro-expander for static methods
Zillion, a proof of concept for fixed-point
ZillionComplex, not just real
Margaret, a converter from infix to S-expressions
The gather key-word for Margaret
License, revision date, and e-mail address

Introduction

Programming ought to be fun, and that includes using a compiler-compiler. DollarAlternCatena is tiny, and I am only an amateur, and I use it all by myself to work on little interpreters and macro-expanders. Actually, DollarAlternCatena is a macro-expander itself, and it knows only three macros: dollar, altern, and catena. It is one Java™ file containing one class. At the time of my typing, the length of the source file is 3110 bytes.

Dollar means zero or more examples of. (In the fifties it was an actual dollar sign.) For example,

multSimpleOrDivSimples dollar multSimpleOrDivSimple
means that multSimpleOrDivSimples is a private static void method with no arguments which repeatedly calls the multSimpleOrDivSimple method until the multSimpleOrDivSimple method fails. Then the multSimpleOrDivSimples method declares success and returns. Here is what multSimpleOrDivSimples looks like after macro-expansion:
private static void multSimpleOrDivSimples(){ do{ multSimpleOrDivSimple(); } while( toggle==true );  toggle=true; }
Notice please that one line expands to one line. This is so line numbers will be the same before and after macro-expansion, so that diagnostics will be understandable. The “toggle” variable is a boolean which is true for success and false for failure. This toggle is not part of DollarAlternCatena. It must be declared in the file being macro-expanded.

Altern means at least one of the list must succeed, or else there is a failure. For example:

multSimpleOrDivSimple altern multSimple divSimple
means that multSimpleOrDivSimple is a private static void method with no arguments. If multSimple succeeds then multSimpleOrDivSimple succeeds, or else if divSimple succeeds then multSimpleOrDivSimple succeeds, or else multSimpleOrDivSimple fails. Here is multSimpleOrDivSimple after expansion:
private static void multSimpleOrDivSimple(){  multSimple(); if( toggle ){ return; } divSimple(); if( toggle ){ return; } }

Catena is in a way the opposite of altern. If anything in the catena list fails, then the whole catena fails. A catena may contain semantic code. This code is enclosed in curly braces. Semantic code is not part of the list, so it cannot cause the catena to fail. For example:

multSimple catena match("times") simple { stackPointer--; stack[stackPointer]*=stack[stackPointer+1]; }
means that multSimple is a private static void method with no arguments. It calls match("times") and it calls simple. If both succeed, then multSimple works the semantic code and succeeds. Otherwise multSimple fails. Here is multSimple after expansion:
private static void multSimple(){  match("times"); if( toggle==false ){ return; } simple(); if( toggle==false ){ erroneous(); } stackPointer--; stack[stackPointer]*=stack[stackPointer+1]; }
The “match” method must be in the file being expanded; match is not part of DollarAlternCatena. If the tokenPointer is pointing to the String “times” then match increments the tokenPointer and succeeds and returns. Else match fails. Similarly the “erroneous” method must be in the file being expanded. It throws an Error. All the examples in this section are copied from the SlideRule.dac and SlideRule.java files.

DollarAlternCatena inputs a file to be macro-expanded on the standard input, and it outputs the result on the standard output. I include a Microsoft Windows batch file called “dac.bat” to reduce human typing. (Users of Unix and Linux will know how to change my batch file.) For example, to input SlideRule.dac and output SlideRule.java and compile SlideRule.java to SlideRule.class, just please type at the Dos prompt

set lefty=SlideRule
dac.bat
Here I am assuming that the SlideRule.dac file is in the local folder (directory) and that javac.exe is in the path.

All of the programs built by DollarAlternCatena are top-down syntactic recognizers without any back-track.

To top

Download and install

To download just please click on DollarAlternCatena.zip. To install, just please unzip the zip file. To uninstall, just delete the files.

I include .class files compiled with Java 1.6 . Please use Java 1.6 or later, because Oracle does not support earlier Javas.

To top

SlideRule, a pseudo slide rule

Real slide rules work by logarithms. SlideRule is a program running on an electronic digital computer. However, SlideRule arithmetic has many more digits than a real slide rule. For example, let us divide 2 by 3 and then multiply by pi. If we are at a Dos prompt and if SlideRule.class is in the local directory, then we may type at the prompt
java SlideRule 2 over 3 times pi
and the program will type
2.0943951023931953
That is many more digits than any real slide rule can do. The only operators permitted are times and over. They multiply and divide. They associate to the left, just as in Java. It is not possible to use the asterisk for multiplication at the Dos prompt, except by putting it in quotes, and quotes look absurd. Operands may be pi or any Java-style “double” number.

In order to start with a small intepreter, I have not included any other operators but times and over. Even parentheses are forbidden. Do please remember to use blanks to separate. That is, the user is asked to break the input into tokens. DollarAlternCatena has no built-in lexer.

To top

Calculator, an incomplete calculator

Calculator is just SlideRule with more features. In particular, it can do parentheses. That means that the syntactic methods are recursive. The operators are plus, minus, times, over, and pow. (The plus and the minus may be either binary or singulary.) The pow operator is the power. Also, there is a sqrt function. For example, one may type at the Dos prompt
java Calculator 1 over ( 2 pow 3.2 plus 3.4e-1 ) minus sqrt ( 88.8 )
and get
-9.318438847807467
Please do put white-space around those parentheses. Everything needs white-space around it.

I call Calculator incomplete because it has only one function in its library: sqrt. This is to encourage users to add what singulary functions they please.

To top

Stat, a macro-expander for static methods

Stat.dac is much like SlideRule.dac and Calculator.dac, but it works on Strings instead of on numbers. In particular, its “stack” is an array of Strings. These Strings represent formulas which are calls of static methods. For example, if the input file contains the line
stat BigInteger check = x * x
then the corresponding output line will be
BigInteger check = multiply(x,x);
If the input file contains the line
stat x = x - ( x * x - radicand  ) / ( two * x - zero  )
then the corresponding output line will be
x = subtract(x,divide(subtract(multiply(x,x),radicand),subtract(multiply(two,x),zero)));
(These examples are from Zillion.stat and Zillion.java .) The reader sees that Stat converts infix notation to calls of static functions. It does not build the static functions themselves. Those ought to be in the input file, or in some other file.

The binary operators that Stat knows about are + - * / and **. These are converted into calls of add, subtract, multiply, divide, and pow. Also Stat knows about the singulary “-” sign, and it converts it into a call of negate. Also, Stat knows about parentheses. It does not know about variables and numbers, so it trustingly assumes that any token it does not know about may be used as an argument of a method call. I am speaking of the right hand side of the equal sign. On the left hand side, Stat assumes that tokens are variable names or class names or primitive type names or modifiers. Please do not worry about this simplicity. If any grammatical errors are not caught by Stat, javac will catch them.

Stat inputs a file to be macro-expanded on the standard input, and it outputs the result on the standard output. I include a Microsoft Windows batch file called “stat.bat” to reduce human typing. (Users of Unix and Linux will know how to change my batch file.) For example, to input Zillion.stat and output Zillion.java and compile Zillion.java to Zillion.class and execute Zillion.class, just please type at the Dos prompt

set left=Zillion
stat.bat
Here I am assuming that the Stat.class and Zillion.stat files are in the local folder (directory) and that javac.exe is in the path.

One thing more, please. A call of the “stat” macro has no semicolon. The semicolon will be put on by the Stat program.

To top

Zillion, a proof of concept for fixed-point

Eight decimal digits and sixteen decimal digits are useful, but sometimes they do not suffice, and the scientist or engineer needs more. Java has a mode called BigInteger which can do arithmetic of any size, but it can do whole numbers only. Also, it cannot take infix notation. I propose to disguise decimal fractions as BigIntegers by multiplying each by a large power of ten, which I will call zillion. Also I must write some static methods to do arithmetic on my disguised numbers, using the non-static methods of BigInteger. For add and subtract and negate, we can just use the methods of BigInteger. For multiply and divide we must think a little. If I multiply 3 zillion by 5 zillion, I will get 15 zillion zillion, which is wrong, so I must then divide by a zillion and get 15 zillion, the right answer. Divide works backwards. To divide 15 zillion by 3 zillion, I must first multiply by a zillion, getting 15 zillion zillion. Then I divide by 3 zillion to get 5 zillion, the right answer. I have not written a pow method for Zillion.

I have written a file called Zillion.stat to demonstrate this. I have used the hundredth power of ten as my value of zillion. Also the file contains a main method showing Newton’s loop to take the square root of 37. It looks like this:

public static void main( String[] args )
{
BigInteger x=new BigInteger( "1" ).multiply( zillion );
BigInteger radicand=new BigInteger( "37" ).multiply( zillion );
BigInteger two=new BigInteger( "2" ).multiply( zillion );
BigInteger zero=new BigInteger( "0" ).multiply( zillion );

	for( int j=0;j<15;j++ )
	{
	stat x = x - ( x * x - radicand  ) / ( two * x - zero  )
	System.out.println( "" );
	System.out.println( "j  "+j );
	System.out.println( "x  "+x );
	stat BigInteger check = x * x
	System.out.println( "check  "+check );
	}
}
The last time around the loop, the display is
j  14
x  60827625302982196889996842452020670620849700947864111864191530464863327253189102398030664279578486635
check  370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008

To top

ZillionComplex, not just real

Real numbers are not enough. Electrical engineers (and many other engineers and scientists) need complex mode. I merely add a few methods to Zillion’s methods. I represent complex numbers by using arrays of two real numbers, one for real part and the other for imaginary part. Also I change the main method to take advantage of the new methods. The main method now looks like
public static void main( String[] args )
{
BigInteger[] x=buildComplex( "1","2" );
BigInteger[] radicand=buildComplex( "37","28" );
BigInteger[] two=buildComplex( "2","0" );
BigInteger[] zero=buildComplex( "0","0" );

	for( int j=0;j<30;j++ )
	{
	stat x = x - ( x * x - radicand  ) / ( two * x - zero  )
	System.out.println( "" );
	System.out.println( "j  "+j );
	System.out.println( "x  " + toString(x) );
	stat BigInteger[] check = x * x
	System.out.println( "check  " + toString(check) );
	}
}
The last time around the loop, the display looks like
j  29
x  [ 64575704035062878278583510632551419100285233330264022866587450133600992758669471932216266522049839913 , 21679980434124844925518867991343731656298881192090294182928717611446799999629920479734470260080735516 ]
check  [ 370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023 , 280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028 ]

To top

Margaret, a converter from infix to S-expressions

My reason for choosing the name “Margaret” is in the last paragraph of this section.

The previous examples on this page were for converting into the Java language. This section is about converting into the S-expressions of the Scheme language. Each line to be converted must begin with the word “margaret” without the quotes. Please notice that margaret is all in lower case. Here is an example:

margaret denominator define cos ( sin ( x ) ) * cos ( x ) - sin ( x )
It is to be converted to
( define denominator ( - ( * ( cos ( sin x ) ) ( cos x ) ) ( sin x ) ) )
The grammar for Margaret is in Margaret.dac and Dac.class converts it to Margaret.java . Then javac compiles it to Margaret.class .

Suppose now that I wish to run a Newton loop to solve the equation “sin ( sin ( x ) ) + cos ( x ) - .5 = 0”. I write the file newtonLoop.margaret and type at the dos prompt

java Margaret < newtonLoop.margaret > newtonLoop.scm
This will convert it to newtonLoop.scm . Then I can start up my favorite Scheme interpreter or compiler. My favorite is Chicken Scheme. It comes with both a compiler and an interpreter. The compiler makes really speedy binary files, but those binary files cannot run inside an “integrated development environment” (IDE) because there will be a segmentation fault. Binary files made by the compiler can do “call/cc” correctly, but the interpreter can not. The interpreter can work inside an IDE.

There are of course many other Scheme implementations, and doubtless each one of them is the favorite of some reader. If Margaret fails with some Scheme, I respectfully request the user to let me know about it.

I had better explain a few details of Margaret. The “define” and “set!” tokens have about the same syntax as the single equal sign “=” of Java. The “**” and “expt” tokens have about the same syntax as the “^” of Basic. (Margaret changes ** to expt.) All four of these tokens associate to the right. The “and” and “or” tokens do not associate with each other or with themselves. To have more than one “and” or “or” in a logical expression, one must use parentheses. As always, I remind the reader that tokens must be separated by white-space.

Now it is time for me to explain why I used the name Margaret. It is from Greek, and it means “pearl.” Since the year 2000 I have wished and wished for Perl 6 to be finished so I could have fun using it. It is not finished. However, nearly all the things Perl 6 ought to do are already done by Scheme, including (ir)regular expressions, proper tail recursion, continuations, and interpolations using “quasiquote” and “unquote.” However, Scheme does not have infix formulas making use of precedence. Many Scheme programmers have tried to add this on, but, in my opinion, they have all come up short. I believe that this is because they attempted to do the trick in Scheme. I have instead used Java because I am a mediocre Java programmer but I am ridiculously weak in Scheme. I respectfully thank the reader of this paragraph for her patience with me.

To top

The gather key-word for Margaret

Infix notation is not the only thing that Scheme needs. Another is better output format. Let us suppose that we wish to write a Scheme program to make numbers and strings, and then pass them to a graphics interpreter, in order to draw a magenta limaçon curve with gray “x” and “y” axes. It may be, and often is, that the graphics interpreter does not know how to understand parentheses. It is, perhaps, expecting most lines to consist of two numbers and a string, separated by one or more blanks. The numbers are the values of “x” and “y,” and the string is a color name. Outputting a Scheme “list” will not work.

On each output line, what is needed is six examples of “display.” That is too much typing for a human to do. The “gather” keyword is built for this. First, please, look at the graphIt.margaret file. It has three “gather” lines. The first makes dots for the “x” axis, the second makes dots for the “y” axis, and the third makes dots for the limaçon curve itself. Now instead please look at the graphIt.scm file. Where the “gathers” used to be, we now see “display” lines. Those lines would be more typing than a human ought to do.

There is nothing magic about the words “separator” and “linemark.” They are merely names of variables. The programmer can use whatever variable names she chooses. I have used long names, but perhaps she prefers shorter. The tokens following the key-word “gather” must be either variable names or else constants having no blanks inside them. S-expressions and infix expressions are forbidden.

To top

License, revision date, and e-mail address

I don’t know how much copyright Oracle retains in the compiled .class files. All the other files in the present collection are in the public domain. Java™ is of course the property of Oracle. The date of this revision is 8 March 2012. Comments both constructive and destructive come to me, Harold Kaplan,
       at     dot
smtw2gh  gmail   com
For other links to Harold Kaplan’s programs, click on programming.htm.

For many more links for languages connected with Java, click on http://www.is-research.de/info/vmlanguages/.

To top