The Aldor grammar is defined in this file: axl.z
- zaccgram.y is the grammar driving the expansion.
- cparse.y is a c grammar; most likely unused these days.
Lexing is done by aldor/src/scan.c, with token.c providing the datatype. The slightly weird bit is simply that lex isn't used, but instead it's directly written in C (IIRC because it was no harder to write in C than lex and more flexible which helps with indentation sensitivity). I suspect that a fricas scanner would do a sufficiently good job with aldor, providing semantic markup was added later.
Aldor IDE
The reason that I am interested in the grammar is that I am working on an Aldor IDE using Xtext, this is driven by the grammar.
My code is here
I don't have any java code representing types - at runtime it isn't required. Generating code from an EMF model is perhaps a doable thing, but getting an EMF model is, I expect, a very large project (essentially the top half of the compiler). Hence I think it's better to work one level down, using the aldor compiler as a source of semantic information.
Grammar
I have tried to link the 'railroad' diagrams for each rule together in the following diagram. This is a bit too big and does not fit on this page but it gives some idea of the complexity of the grammar.
Grammar Top Level
At the top level we can have individual expressions/statements or function defintions or we can have domain definitions.
Function Definition
Here is an example of a fuction definition to show how it is parsed.
Structure of Domains
'with' and 'add'
The interface is specified by the 'with' construct.
The 'add' expression creates a domain from a sequence of definitions.
Domain(Arg: ArgType): Type with {
} == add {
}
ChessPiece: with { bestMoves: (Board, %) -> MoveTemplate; ++ `bestMoves p' suggests the best moves in the ++ given position. legalMoves: (Board, %) -> MoveTemplate; ++ `legalMoves p' generates quasi-legal moves. ++ It does not handle en passant or castling. value: (Board, %) -> DoubleFloat; ++ This is a score which estimates the current ++ value in the given position. } == add { ... }
'where'
'where' can be used to add a variable or function to an already existing domain. | bobfun(bob: Object BasicType): () == f avail bob where f(T: BasicType, t: T) : () == { print << "This prints itself as: " << t << newline; } |
Custom Lexer
Implicit Semicolons
According to the Aldor User Guide: "An implicit semicolon is assumed, if possible, after a closing brace. This is determined by whether the following token may start a new expression."
I have worked out how to customise the lexer in Xtext by implementing this code.
This allows me to customise nextToken() which allows me to do a lot of customisation (provided it does not need too much lookahead).
I have already implemented this phantom semicolon insertion after curly brackets, but not the exceptions.
In Aldor this is done in linear.c. This is a pass after tokenisation and before parsing.. idea is that it deals with pile mode, but as a bonus adds semicolons. This happens around line 1060.
Looks like it uses tokInfoTable to lookup flags like isFollower, isOpener, isCloser and so on for each type of token so I will implement this table in java.
Converting axl.z to xtext
First thing is to substitute any rule parameters.