The starting point for this Flat Modelica grammar is the ANTLR grammar for Modelica as proposed by this ModelicaSpecification PR.
The intention is to develop the Flat Modelica grammar as a modification (mainly consisting of restrictions) of the full Modelica grammar, and to make the differences clearly visible in this document. Hence, rather than just erasing the parts of the Modelica grammar that shouldn't be brought to Flat Modelica, these parts will be marked with a strikeout.
The start rule of the Flat Modelica grammar below is flat-modelica.
Each grammar rule is written as a block quote. Regular expressions for tokens are written as inline code
, literal tokens are written in upright boldface (this is useful for avoiding the use of regular expressions when doing so would require protection of active characters), production rule names are written in italics, while parsing constructs are written in plain text.
Parsing constructs:
- x | y — alternatives; either x or y
- x y — sequencing; x followed by y
- x* — zero or more repetitions
- x+ — one or more repetitions
- x? — zero or one repetitions
- EOF — end of file
- (…) — parentheses for grouping
Repetition posfix operators have higher precedence than sequencing, which in turn has higher precedence than alternatives.
To avoid risk of confusion with the parentheses parsing construct ( a | b ), literal parentheses are written in regular expression form, [(]
a | b [)]
, rather than in upright boldface, ( a | b ).
There are no empty productions. Hence, where there is no risk of ambiguity, the left side of an alternative is allowed to be ommitted, meaning the same as just having the right side alternative. For example, ( | a | b ) is the same as ( a | b ).
WS → (
[ ]
|\t
| NL )+
LINE-COMMENT →
//[^\r\n]*
(NL | EOF)
ML-COMMENT →
/[*]([^*]|([*][^/]))*[*]/
NL →
\r\n
|\n
|\r
IDENT → NONDIGIT ( DIGIT | NONDIGIT )* | Q-IDENT
NONDIGIT →
_
|[a-z]
|[A-Z]
STRING →
"
( S-CHAR | S-ESCAPE )*"
The S-CHAR accepts Unicode other than " and \:
S-CHAR → NL |
[^\r\n\\"]
DIGIT →
[0-9]
Q-IDENT →
'
( Q-CHAR | S-ESCAPE ) ( Q-CHAR | S-ESCAPE |"
)*'
Q-CHAR → NONDIGIT | DIGIT |
[-!#$%&()*>+,./:;<>=?>@[]{}|~ ^]
S-ESCAPE →
\\['"?\\abfnrtv]
UNSIGNED-INTEGER → DIGIT+
EXPONENT → (
e
|E
) ([+]
|-
)? DIGIT+
UNSIGNED-NUMBER → DIGIT+ (
[.]
(DIGIT)* )? ( EXPONENT )?
flat-modelica →
VERSION-HEADER
package IDENT
( class-definition ;
| global-constant ;
)*
model long-class-specifier ;
end IDENT ;
Here, the VERSION-HEADER is a Flat Modelica variant of the not yet standardized language version header for Modelica proposed in MCP-0015:
VERSION-HEADER →
^\U+FEFF?//![ ]flat[ ][0-9]+[.][0-9]+[r.][0-9]+$
The \U+FEFF?
at the very beginning is an optional byte order mark.
The IDENT in the flat-modelica rule must be the same identifier as in the long-class-specifier following model.
As an example of the flat-modelica rule, this is a minimal valid Flat Modelica source:
//! flat 3.5.0
package _F
model _F
end _F;
end _F;
class-definition →
encapsulated?class-prefixes class-specifier
class-prefixes →
partial?
(
| type
|operator?record
| ( ( pure constant? ) | impure )?operator?function
| class
| model
| block
| expandable? connector
| package
| operator
)
class-specifier → long-class-specifier | short-class-specifier | der-class-specifier
long-class-specifier
→ IDENT string-comment composition end IDENT
| extends IDENT class-modification? string-comment composition end IDENT
short-class-specifier →
IDENT =
( base-prefix? type-specifierarray-subscripts?class-modification?
| enumeration[(]
( enum-list? | : )[)]
)
comment
der-class-specifier → IDENT = der
[(]
type-specifier , IDENT ( , IDENT )*[)]
comment
base-prefix → input | output
enum-list → enumeration-literal ( , enumeration-literal )*
enumeration-literal → IDENT comment
composition →
(generic-element ;)*
( public (generic-element ;)*
| protected (generic-element ;)*
| equation ( equation ; )*
| initial equation ( initial-equation ; )*
| initial? algorithm ( statement ; )*
)*
( external language-specification?
external-function-call? annotation-comment? ;
)?
( annotation-comment ; )?
language-specification → STRING
external-function-call → ( component-reference = )? IDENT
[(]
expression-list?[)]
generic-element →
import-clause | extends-clause |normal-element | parameter-equation
normal-element →
redeclare?
final?
inner? outer?
(class-definition
| component-clause
| replaceable ( class-definition | component-clause ) ( constraining-clause comment )?
)
parameter-equation →
parameter equation guess-value =
( expression | prioritize-expression )
comment
guess-value → guess
[(]
component-reference[)]
import-clause →
import
( IDENT = name
| name ([.]
([*]
| { import-list } ) |[.][*]
)?
)
comment
import-list → IDENT ( , IDENT )*
extends-clause → extends type-specifier class-modification? annotation-comment?
constraining-clause → constrainedby type-specifier class-modification?
component-clause → type-prefix type-specifier
array-subscripts?component-list
global-constant → constant type-specifier array-subscripts? declaration comment
type-prefix →
( flow | stream )?
( discrete | parameter | constant )?
( input | output )?
component-list → component-declaration ( , component-declaration )*
component-declaration → declaration
condition-attribute?comment
condition-attribute → if expression
declaration → IDENT array-subscripts? modification?
modification
→ class-modification ( = expression )?
| = expression
| := expression
class-modification →
[(]
argument-list?[)]
argument-list → argument ( , argument )*
argument
→ element-modification-or-replaceable
| element-redeclaration
element-modification-or-replaceable →
each?
final?
( element-modification
| element-replaceable
)
element-modification → name modification? string-comment
element-redeclaration →
redeclare each?final?
( short-class-definition
| component-clause1
| element-replaceable
)
element-replaceable →
replaceable
( short-class-definition
| component-clause1
)
constraining-clause?
component-clause1 → type-prefix type-specifier component-declaration1
component-declaration1 → declaration comment
short-class-definition → class-prefixes short-class-specifier
equation →
( simple-expression ( = expression )?
| if-equation
| for-equation
| connect-clause
| when-equation
)
comment
initial-equation → equation | prioritize-equation
statement →
( component-reference ( := expression | function-call-args )
|[(]
output-expression-list[)]
:= component-reference function-call-args
| break
| return
| if-statement
| for-statement
| while-statement
| when-statement
)
comment
if-equation →
if expression then
( equation ; )*
( elseif expression then
( equation ; )*
)*
( else
( equation ; )*
)?
end if
if-statement →
if expression then
( statement ; )*
( elseif expression then
( statement ; )*
)*
( else
( statement ; )*
)?
end if
for-equation →
for for-index loop
( equation ; )*
end for
for-statement →
for for-index loop
( statement ; )*
end for
for-indices → for-index ( , for-index )*
for-index → IDENT in expression
while-statement →
while expression loop
( statement ; )*
end while
when-equation →
when expression then
( equation ; )*
( elsewhen expression then
( equation ; )*
)*
end when
when-statement →
when expression then
( statement ; )*
( elsewhen expression then
( statement ; )*
)*
end when
connect-clause → connect[(]
component-reference , component-reference[)]
prioritize-equation → prioritize
[(]
component-reference , priority[)]
prioritize-expression → prioritize
[(]
expression , priority[)]
priority → expression
expression → simple-expression | if-expression
if-expression →
if expression then expression
( elseif expression then expression )*
else expression
simple-expression → logical-expression ( : logical-expression ( : logical-expression )? )?
logical-expression → logical-term ( or logical-term )*
logical-term → logical-factor ( and logical-factor )*
logical-factor → not? relation
relation → arithmetic-expression ( relational-operator arithmetic-expression )?
relational-operator → < | <= | > | >= | == | <>
arithmetic-expression → add-operator? term ( add-operator term )*
add-operator → + | - | .+ | .-
term → factor ( mul-operator factor )*
mul-operator → ** * ** | ** / ** | ** .* ** | ** ./ **
factor → primary ( (^ | .^) primary )?
primary
→ UNSIGNED-NUMBER
| STRING
| false
| true
| ( der | initial | pure ) function-call-args
| component-reference function-call-args?
|[(]
output-expression-list[)]
array-subscripts?
|[[]
expression-list ( ; expression-list )*[]]
| { array-arguments }
| end
type-specifier → .? name
name → IDENT ( . IDENT )*
component-reference → .? IDENT array-subscripts? ( . IDENT array-subscripts? )*
function-call-args →
[(]
function-arguments?[)]
function-arguments
→ expression ( , function-arguments-non-first | for for-index )?
| function-partial-application ( , function-arguments-non-first )?
| named-arguments
function-arguments-non-first
→ function-argument ( , function-arguments-non-first )?
| named-arguments
array-arguments → expression ( ( , expression )* | for for-index )
named-arguments → named-argument ( , named-argument )*
named-argument → IDENT = function-argument
function-argument
→ function-partial-application
| expression
function-partial-application → function type-specifier
[(]
named-arguments?[)]
output-expression-list → expression? ( , expression? )*
expression-list → expression ( , expression )*
array-subscripts → [ subscript ( , subscript )* ]
subscript → : | expression
comment → string-comment annotation-comment?
string-comment → ( STRING ( + STRING )* )?
annotation-comment → annotation class-modification