time
: '@' NUMBER
| '@' '+' NUMBER
;
: '@' NUMBER
| '@' '+' NUMBER
;
The rest of each section is a set of constraints. Now, I start to get afraid a little bit of the constraint satisfaction, so I restrict constraints to "what we probably need." That may be a bad mistake, because it introduces ad-hoc restrictions to the expressiveness of the language; or it may be a very good idea, because it makes constraint satisfaction possible at all. We'll see ...
I try to separate vector and scalar expressions as far as possible; and I try to separate equality constraints from looser constraints, so I start like that:
constraint
: vectorexpr
'='
vectorexpr
';'
| scalarexpr
'='
scalarexpr
';'
| IDENT: vectorexpr
'='
vectorexpr
';'
| scalarexpr
'='
scalarexpr
';'
('<' | '>' | '<=' | '>=')
scalarexpr
';'
;
For the expressions, we define a standard hierarchy to capture operator precedence:
vectorexpr
: vectorexpr2
( ( '+'
| '-'
)
vectorexpr2
)*
;
vectorexpr2
: vectorexpr3
( ROTATE
'('
: vectorexpr2
( ( '+'
| '-'
)
vectorexpr2
)*
;
vectorexpr2
: vectorexpr3
( ROTATE
'('
scalarexpr
')'
)*
;
vectorexpr3
: '-' vectorexpr4
| vectorexpr4
;
vectorexpr4
: '('
vectorexpr
')'
)*
;
vectorexpr3
: '-' vectorexpr4
| vectorexpr4
;
vectorexpr4
: '('
vectorexpr
')'
| ...simple vector expressions...
;
and
: scalarexpr2
( ( '+'
| '-'
)
scalarexpr2
)*
;
scalarexpr2
: scalarexpr3
( ( '*'
| '/'
)
scalarexpr3
)*
;
scalarexpr3
: '-' scalarexpr4
| scalarexpr4
;
scalarexpr4
: '('
scalarexpr
')'
| ...simple scalar expressions...
;
What simple expressions do we need? Let us start with the vector expressions:
- A constant vector.
- An "anchor" which was defined in the object definitions.
- And an integral and differential.
| INTEGRAL
'(' vectorexpr ')'
| DIFFERENTIAL
'(' vectorexpr ')'
| constvector
| anchor
;
'(' vectorexpr ')'
| DIFFERENTIAL
'(' vectorexpr ')'
| constvector
| anchor
;
We have already defined a constvector. An anchor, right now, is simply an object IDENT and an anchor IDENT (but I think that I have to introduce compound objects later, when the number of moved objects increases):
anchor
: object '.' IDENT
;
object
: IDENT
;
For the simple scalar expressions, we should at least provide the following:
| INTEGRAL
'(' scalarexpr ')'
| DIFFERENTIAL
'(' scalarexpr ')'
| ANGLE
'(' scalarexpr ')'
| DIFFERENTIAL
'(' scalarexpr ')'
| ANGLE
'('
vectorexpr
','
vectorexpr
')'
| NUMBER
| IDENT
| '_' // the dont care variable
| anchor
vectorexpr
','
vectorexpr
')'
| NUMBER
| IDENT
| '_' // the dont care variable
| anchor
( X
| Y
)
| object COLOR
| T
| IV
;
| IV
;
With this, it should now be possible to run our complete script for the slider-crank mechanism throught the parser!
UPDATE: The test revealed two errors:
The first one is a "syntactical" one: ANTLR uses the rule names as method names. But this creates a C# syntax error for the rule object (which is a keyword in C#). So I replaced object with thing.
The other error is a too restrictive rule for vector expressions: As one possibility of a simple vector expression, I took constvector. However, in the timeline, we obviously also want to use non-const vectors, e.g. in the constraint Engine.Q = Engine.P + [_,0]. Therefore, the rule actually is
...
| DIFFERENTIAL
'(' vectorexpr ')'
| vector
| anchor
...
with
vector
: '['
scalarexpr
','
scalarexpr
']'
;
The grammar at this stage can be downloaded here.
No comments:
Post a Comment