3 OpenModelica Compiler Design

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

3.1 Modelica Translation Stages

The translation process of Modelica code to a simulation executable is schematically depicted in figure 1 below.


Translationstages

Figure 1: Translation stages from Modelica code to executing simulation.


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.

3.2 Simplified Overall Structure of the Compiler

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.

3.3 The front end

3.3.1 Parsing and Abstract Syntax

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:

uniontype Program 
  record PROGRAM 
    list<Class> classes; 
  end PROGRAM; 
end Program;

The Absyn.Class type contains the name of the class, the class’ prefixes and the body of the class:

uniontype Class 
  record CLASS 
    Ident       name; 
    Boolean     partialPrefix; 
    Boolean     finalPrefix; 
    Boolean     encapsulatedPrefix; 
    Restriction restriction; 
    ClassDef    body; 
    Info        info; 
  end CLASS; 
end Class;

Something to note is that the type also contains an Absyn.Info object, which contains information about where an AST element was found:

uniontype Info 
  record INFO 
    String fileName; 
    Boolean isReadOnly; 
    Integer lineNumberStart; 
    Integer columnNumberStart; 
    Integer lineNumberEnd; 
    Integer columnNumberEnd; 
    TimeStamp buildTimes; 
  end INFO; 
end Info;

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:

uniontype ClassPart 
  record PUBLIC 
    list<ElementItem> contents; 
  end PUBLIC; 
 
  record PROTECTED 
    list<ElementItem> contents; 
  end PROTECTED; 
 
  record EQUATIONS 
    list<EquationItem> contents; 
  end EQUATIONS; 
 
  record ALGORITHMS 
    list<EquationItem> contents; 
  end ALGORITHMS; 
end ClassPart;

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:

uniontype ElementSpec 
  record CLASSDEF 
    Boolean replaceable_; 
    Class class_; 
  end CLASSDEF; 
 
  record COMPONENTS 
    ElementAttributes attributes; 
    TypeSpec typeSpec; 
    list<ComponentItem> components; 
  end COMPONENTS; 
end ElementSpec;

Parsing a Modelica model such as

model M 
  Real x, y; 
equation 
  x = y; 
equation 
  y = 2; 
end M;

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.

3.3.2 Rewriting the AST into SCode

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:

type Program = list<Element>;

The SCode.Element type represents the different types of elements, such as classes and components:

uniontype Element 
  record CLASS 
    Ident             name; 
    Prefixes          prefixes; 
    Encapsulated      encapsulatedPrefix; 
    Partial           partialPrefix; 
    Restriction       restriction; 
    ClassDef          classDef; 
    Absyn.Info        info; 
  end CLASS; 
 
  record COMPONENT 
    Ident             name; 
    Prefixes          prefixes; 
    Attributes        attributes; 
    Absyn.TypeSpec    typeSpec; 
    Mod               modifications; 
    Option<Comment>   comment; 
    Option<Absyn.Exp> condition; 
    Absyn.Info        info; 
  end COMPONENT; 
end Element;

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.

3.3.3 Model Flattening and Instantiation

3.4 The back end

3.5 Scripting MetaModelica

Describes the Interactive module.