mbeddr: Embedded-Entwicklung mit erweiterbarem C

Werkzeuge  –  15 Kommentare

Was wäre, wenn Sprachen genau so einfach erweiterbar wären wie Programme? Der Artikel zeigt im Kontext eingebetteter Systeme, wie sich mit der IDE mbeddr die Programmiersprache C erweitern lässt.

Entwickler sind es gewöhnt, ihr Programm bei Bedarf einfach unter Verwendung zusätzlicher Bibliotheken zu entwickeln. Diese haben allerdings den Nachteil, dass sie keine domänenspezifische Syntax, statischen Constraints oder Typregeln mitbringen und auch die IDE nicht erweitern. Spracherweiterungen können dieses Manko beheben, und Language Workbenches sind in der Lage, derartige inkrementelle Spracherweiterung umzusetzen. Mit ihnen lassen sich Sprachen effizient entwickeln, kombinieren und verwenden.

Die Entwicklung eingebetteter Systeme stellt die folgenden Herausforderungen an den Entwickler:

  • Abstraktionen ohne Laufzeit-Overhead: Gute Abstraktionen führen zu weniger Code und zu besserer Analysier- und Wartbarkeit. In eingebetteten Systemen sind derartige Abstraktionen allerdings mit möglich wenig Laufzeitkosten umzusetzen, da die Ressourcen auf den Zielgeräten üblicherweise beschränkt sind.
  • C ist gefährlich: Die verbreitetste Programmiersprache für eingebettete Systeme hat durchaus einige Mängel, die bei Embedded-Systemen zu ernsthaften Problemen führen können. Dazu gehören zum Beispiel Void-Pointer und die unkontrollierte Verwendung des Präprozessors.
  • Programm-Annotationen: Programme in technischen Domänen benötigen oft zusätzliche Spezifikationen für Typen oder Variablen. Dazu gehören Größenbeschränkungen, physikalische Einheiten, oder Zugriffsbeschränkungen. Sie lassen sich in C nicht sinnvoll an den entsprechenden Typen oder Variablen anbringen, das Auslagern in XML-Dateien verbessert die Situation ebenfalls nicht.
  • Verifikation: Eingebettete Software existiert oft im Kontext sicherheitskritischer Systeme. Dort ist die Software vor dem Einsatz möglichst umfangreich auf Korrektheit zu untersuchen. Die Verifikation von C ist teuer, insbesondere durch die Komplexität und den niedrigen Abstraktionslevel der Sprache.
  • Prozessunterstützung: Ein Großteil aller eingebetteter Systeme entsteht im Rahmen von Produktlinien. Um die damit einhergehende Komplexität in den Griff zu bekommen, ist es unter anderem nötig, die Variabilität der Produkte innerhalb der Produktlinie systematisch zu verwalten und eine stringente Nachvollziehbarkeit von den Implementierungsartefakten zu den Anforderungen sicherzustellen.

MPS

MPS zeichnet sich unter anderem durch einen projizierenden Editor aus, der, wie für solche Werkzeuge üblich, ohne Grammatik und Parser auskommt. Dadurch lassen sich unterschiedliche Notationen verwenden: Text, Tabellen, Symbole wie Bruchstriche und Grafiken. Außerdem führt das dazu, dass sich Sprachen einfach modularisieren und kombinieren lassen. MPS wird standardmäßig mit Java ausgeliefert, sodass sich auch Java inkrementell erweitern lässt. Außerdem können Entwickler mit MPS separate DSLs bauen. MPS ist derzeit in Version 2.5 verfügbar und steht unter der Apache-2.0-Lizenz. Für 2013 sind die Integration in Eclipse und die Unterstützung grafischer Notationen geplant.

Aufgrund dieser Anforderungen kommen bei der Entwicklung eingebetteter Systeme oft eine Vielzahl von Werkzeugen zum Einsatz. Ihre Integration führt allerdings zu weiteren Herausforderungen.

Um diese Probleme in den Griff zu bekommen, unterstützt die IDE mbeddr auf Basis von C inkrementelle, domänenspezifische Spracherweiterungen. Die Technik nutzt JetBrains' Language Workbench MPS (Meta Programming System, die die notwendigen Mechanismen zur Verfügung stellt. mbeddr umfasst eine IDE für C und Erweiterungen. Außerdem stellt es einen erweiterbaren Debugger zur Verfügung. Sowohl mbeddr als auch MPS sind als Open-Source-Software verfügbar.

Unter Spracherweiterung versteht man das modulare Hinzufügen neuer Sprachkonzepte. Dabei liegt die Betonung auf modular: Die Basissprache, hier C, darf nicht invasiv verändert werden, um neue Sprachmodule hinzuzufügen. Außerdem sollten sich unabhängig voneinander entwickelte Spracherweiterungen nicht gegenseitig stören. Das hat insbesondere zur Folge, dass die Komposition unabhängig entwickelter Syntaxbeschreibungen nicht zu ungültigen Sprachen führen darf. Bei Verwendung klassischer Parsergeneratoren ist das ein Problem, bei projizierenden Editoren tritt das nicht auf.

Neue, typischerweise abstraktere oder domänenspezifische Sprachkonstrukte werden im Rahmen von Transformationen auf existierende Sprachkonstrukte zurückgeführt. Das können entweder Konstrukte anderer Erweiterungen oder der Basissprache C sein. Nach dem Zurückführen aller Erweiterungen auf die Basissprache übersetzt ein gewöhnlicher Compiler das Programm. Bei mbeddr kommt entweder gcc oder ein für die Zielplattform passender Compiler zum Einsatz.

mbeddr stellt Syntax-Highlighting, Code Completion und statische Typprüfung zur Verfügung. Das gilt für C, aber auch für Erweiterungen. Im Beispiel ist unter anderem eine Zustandsmaschine und eine Entscheidungstabelle zu sehen. Letztere zeigt die Verwendung nichttextueller Notationen, die MPS mit dem projizierenden Editor unterstützt (Abb. 1).

MPS hat sich als geeignet für diese Art der modularen Spracherweiterung herausgestellt. Das liegt vor allem daran, dass MPS ein projizierende Editor ist, wodurch eine Änderung an einem Programm in ihm direkt zur Änderung des abstrakten Syntaxbaums führt. Die Herausforderung, dass der Parser die Struktur des Baums aus der flachen, sequenziellen Textstruktur (re-)konstruieren muss, fällt weg. Außerdem kann die Komposition unabhängig entwickelter Sprachen nie zu ungültigen Sprachdefinitionen führen. Das führt letztlich zu nahezu unbegrenzter Spracherweiterbarkeit. Des Weiteren sind projizierende Editoren nicht auf textartige Syntaxformen beschränkt. Tabellarische, mathematische oder (zukünftig) grafische Notationen lassen sich ohne konzeptionellen Bruch mit textuellen Notationen integrieren. Siehe hierzu auch die Tabelle in Abbildung 1.