From: waterman@chaos.cs.brandeis.edu (T.S. Waterman)
Subject: Syntax and expressiveness (Re: Accessing the hardware directly
Reply-To: waterman@cs.brandeis.edu
Organization: CAVEAT Labs, Inc.
Date: Tue, 17 Nov 1992 22:17:27 GMT

(I have no idea why I'm joining the fray, but here goes)

hrubin@pop.stat.purdue.edu (Herman Rubin) writes:
>mwm@contessa.palo-alto.ca.us (Mike Meyer) writes:

>>If you don't like the syntax they provide for accessing these
>>facilities, bitch at *them*. Have you called the people who build the
>>machines you use and asked for a more accessible assembler?

>It is not a matter of access, but of SYNTAX.  

It would seem Mr. Meyer was referring not to the physical accessibility
of the assembler, but it's ability to provide access to the 
manipulations you might want to perform. This can be viewed as matching
its syntax to your own notation for manipulating the machine.

  What you've said you want, Mr. Rubin, is a method of extending
a given language's syntax. Those available do not seem to fit your
needs.  What you should be aware of, however, is that the tools
to construct new language syntax, and to modify existing languages, exist.
In fact, they are well developed and are used extensively for
purposes exactly as you have described needing.

>What I have asked for is that the language be fully extensible.  If
>I want to add another type, I do so.  To SOME extent, C has this in
>structs, and C++ does a good job with its classes.  

>> [about writing a language specification]

>I still do not know what you mean by a spec.  I have stated that one
>thing which is certainly going to be needed is a really versatile
>macro converter.
>...

These converters exist, in numerous forms and specializations.
When they get complex and versatile enough, they are usually
referred to as 'compiler generators'.

>Looking at what I have written above, the types certainly will not be
>limited to those in the current languages.  Bob Silverman has given 
>some examples of the notation; he would like to write

>	c = a ** b

>to multiply two integers of a given size to form a double length integer.
>Now in C++ one could insert a function doubmult, and even overload it to
>handle the possibility of different lengths being doubled, and instruct
>the compiler (?) to inline this.  Now with the macro converter, Bob would
>still have to define the function doubmult, but he could also have the
>macro conversion instruction

>### 	a ** b	{
>	doubmult(a,b);}#

>or some other suitable notation, and then he could blithely write a ** b
>in the program wherever he wants to.   Now there are more complicated
>situations.

This is already a very comlicated situation!  While consistently comlaining
about the syntax of available language, you do not seem to show an appreciation
of how difficult it is in the general case to reduce a notation to the 
specific operations you understand it to mean.
  For instance, what priority does this new '**' operation take (what is
its associativity)? when you write  a + b ** c, or even a ** b ** c, what
exactly do you mean. You need to specify this in your macro extension
as well. 
  One problem with this is that the numberous possible syntactic
interactions between various operator specifications adds largely
to the complexity of writing a compiler; more exactly, to the
complexity of that compiler's _parser_. Thus, every time you add a new
operator, you add a large number of possible decisions to
the interpretation of an arbitrary program.


>There is one which even others have cited as "impossible"
>to understand.  I will now endeavor to show that it is not so bad, and
>I will give most of what it is doing, and why.  The syntax is

>	c{'z} ={tc} {-}{|}{ta} a{'x} OP{mod} {|}{tb} b{'y} {/\{~}w}
>	  1     2    3  4   5     6  7   8    9  10    11   12 13

>Since there are so many optional fields, I have numbered them.  Now this
>is what it requires:

> [long list of chioice and switching options for the various fields]

    This situation is far from the impossible. You have demonstrated
that by giving a decision algorithm stating what should be done in
every case.  The fact that you can do so leads me to think that you
can easily write a macro to convert this notation to the appropriate
set of declarations and statements in assembly, or any other
language suitable for specifying such things as odd and even registers
and half or full vectors (whatever they ore).

  C contains, as a set of programs adjuct to the compiler, a
preprocessor, which does lexical substitutions for specific
expressions. It has a very limitted syntax and control structure.
It can be written in less than a page or two of lex/yacc/C.
The most complex thing about it is it's ability to keep track of
the macro names (not very hard, on any scale).

  Obviously, this macro language (for it is a language, seperate from C,
even though it is described in the same texts) is not enough for what
you want to do. Since you, with perhaps a very few others, are the
ones in need of a powerful meta syntax, the answer is obvious:
  Write Your Own.

  Oh Right! you say, I'm going to go write my own language syntax!
Well why not? You did it four paragraphs above. You do it all the
time, specifying notations particular to the problem at hand.
What you don't seem to realize is that you _can_ specify a language
about as easily as you can specify the decision algorithm you gave
for the notation above.
  This is not a brush-off --- I do this all the time.  I've written
4 different interpretters and cross-compilers in the last few months,
simply in order to get work done. They're not major projects.
One was in Lisp, two in prolog, and one I wrote using lex, yacc and C.
It's not very difficult.

  Get yourself a copy of Aho, Sethi and Ullman "Compilers". I think
it's in 3rd edtion by now.  The process of writing a language
specification and implementing a parser and compiler are well described.
From scratch, I bet you can write a cross-compiler from your notation
to C (or whatever) in about 3 weeks, half time. The second one you write
will take 1/3 that time.  You can even write the converter at the
time you're developing the notation for your current problem.


In this way, you'll be able to specify the problem in a notation that
reflects its intrinsic structure (as far as that is reflected in the
notation), and only have to write out those horrendous chunks of 
nested pointer chains once, when you write the compiler. 
This should simplify your life by allowing you to think about the
problem at hand, rather than constantly thinking about how
to convert it into a procedure that runs over your hardware.


>I do not see how any system of references will enable writing

>	*fill(*descriptor)

>any faster. 

How about
	fill(descriptor)  ?

Remeber, the dereferencing of the names 'fill' and 'descriptor'
are done only once, at _compile_ time, and don't take up a single
iota of energy at _run_ time.

--ts
Natural Language and Generative Semantics,
Brandeis Univ.
Waltham, MA 02254