This documentation describes how the OpenModelica compiler is designed. The first section will give a brief overview of the design, and the rest of the sections will go into further detail about the different parts of the compiler in an order that roughly follows the compilation process.
This documentation assumes some familiarity with the MetaModelica language, which most of the compiler is implemented in. If you are not familiar with MetaModelica it might be beneficial to read through the first parts of the MetaModelica documentation in section 2 to become familiar with the MetaModelica syntax and data types. Also note that code examples in this documentation might be incomplete when it’s
The translation process of Modelica code to a simulation executable is schematically depicted in figure 1 below.
Insert references to sections below
The OpenModelica compiler can be seen as divided into a front end and a back end. The input to the front end is Modelica code (typically .mo files), which is parsed and translated to a so-called flat model. This flattening phase removes the object-oriented structure from the model by instantiating the model’s components and performs operations such as inheritance, redeclares, and modifications. It also does type checking, expansion of connect equations, and handles package includes and imports. The result from this instantiation phase is a set of variables, equations, algorithms and functions, with all object-oriented structure removed apart from dot notation within names.
The result from the front end is then passed to the back end, where the first phase is the equation analyzer. In this phase the equations are sorted and transformed from their DAE representation into a Block Lower Triangular DAE form. The sorted equations are then passed to the equation optimizer, which tries to optimize the equations.
The optimized DAE is finally sent to the code generator, which generates code that can be compiled to produce a simulation executable. The default target language is C, but the code generator can be replaced to generate code for other target languages.
The OpenModelica compiler is also capable of compiling MetaModelica code, and the process for doing this is mostly similar to compiling normal Modelica functions with MetaModelica additions. It also handles MetaModelica scripts (.mos files), which is described in section 3.5.
The OpenModelica compiler is separated into a number of modules, implemented as MetaModelica packages. The entry point of the compiler is the Main.main function.
The parser is implemented as an ANTLR 3 grammar [?], and C code for the parser is generated with the ANTLR parser generator tool. The generated parser is then encapsulated by the Parser module, which provides functions for parsing source code either from file or from memory. These functions are implemented as external C functions which calls the generated C code from ANTLR.
The parser builds an Abstract Syntax Tree (AST) from the source code, using the AST data types in the Absyn module. The Parser.parse functions returns an Absyn.Program, which is simply a list of classes:
The Absyn.Class type contains the name of the class, the class’ prefixes and the body of the class:
Something to note is that the type also contains an Absyn.Info object, which contains information about where an AST element was found:
Almost all AST elements contains an Absyn.Info object in some way or another. This is one of a few types that are propagated through the different stages of the compiler, and used when printing error messages to give the user a clue about where the errors are.
The AST closely corresponds to the parse tree and keeps the structure of the source file. The Absyn.ClassDef type can represent several different types of class definitions, but for normal classes it keeps a list of Absyn.ClassPart objects. These class parts represents the different declaration sections that a class might contain, such as public, protected, equation, and algorithm sections:
Modelica classes are allowed to contain multiple sections of the same type, with an implicit public sections first, so the class definition might similarly contain several ClassParts of the same type.
Class elements are ultimately represented by AbsynElementSpec objects, which can represent class definitions, components and other elements:
Parsing a Modelica model such as
will thus produce an Absyn.Program that contains the class M. The class definition for M will contain a public section with the components x and y, and two equation sections: one section for x equals y and another for y equals 2. Note that the x and y components will be stored as a single Absyn.COMPONENTS, since they are declared with the same statement and thus share the same type and attributes.
Since the AST closely follows the structure of the source code it has several disadvantages when it comes to further translations of the code. Multiple class components might e.g. be grouped together into a single element node. A simpler intermediate form is therefore introduced, called SCode, with the purpose of simplifying further translations. The translation from Absyn to SCode is handled by the SCodeUtil package, with the entry point being SCodeUtil.translateAbsyn2SCode. SCode differs in many ways from Absyn, but some notable differences are:
An SCode.Program, the equivalence to Absyn.Program in SCode, is simply defined as a list of SCode.Elements:
The SCode.Element type represents the different types of elements, such as classes and components:
Not all Absyn data structures are translated into SCode ones, as is evident in the code listing above. Some types are already simple enough that they are reused in the SCode, some notable examples being Absyn.Exp, Absyn.TypeSpec, Absyn.Info, Absyn.ComponentRef, and Absyn.Path.
Describes the Interactive module.