Entwicklung & Design

Entwickeln domänenspezifischer Sprachen mit Ruby: Auf dem Weg zur nächsten Programmiersprache

Seite 3 / 5

Es soll die Eingabe „(+ 2 1)“ analysiert und das Ergebnis 3 ausgegeben werden. Außerdem soll zusätzlich Klammerung erlaubt sein, sodass folgender Ausdruck „(+ (- 10 2) 1)“ den Wert 9 zur Folge hat. Wie oben schon erwähnt, wird im ersten Schritt ein Lexer benötigt, der die Eingabemenge in für den Parser verständliche Stückchen zerlegt. Benötigt wird eine Erkennung für die Klammern, die Operatoren und natürlich für die Zahlen. In der Dhaka-Syntax formuliert wird dies zu dem Code in Listing 1.

Lexer
class SimpleLexer < Dhaka::LexerSpecification
	ops = ["+", "-"]; keys = ["(", ")"]
	keys.each { |op|   for_symbol(op) {  create_token(op) } }
	ops.each { |op|  for_symbol(op) {  create_token("OPERATOR")  }}
	for_pattern('\d+') {  create_token('n') }
	for_pattern('\s+') {  }
end

Listing 1

In Zeilen 3 bis 9 werden für die Operatoren (‚+‘,‘-‚) und die Schlüsselwörter (‚(‚, ‚)‘) eigene Token angelegt. Reguläre Ausdrücke definieren dabei, was ein Token ist, bevor dieses angelegt wird. Whitespaces wie Zeilenumbrüche und Leerzeichen werden ignoriert. Damit ist der Lexer spezifiziert, welcher die Eingaben für den Parser vorbereitet.

BNF-Schreibweise der Grammatik
_Start_ : Expr
Expr :  (   OPERATOR   Expr   Expr ) | n

Listing 2

Nun muss die Grammatik definiert werden. Sie muss Ausdrücke erkennen, also zuordnen, dass eine Folge von Klammer, Operator, Zahl, Zahl und Klammer einen Ausdruck bildet. Zusätzlich dazu ist noch das Erkennen von Schachtelung zu ermöglichen. In der BNF-Schreibweise (eine spezielle Art, Ableitungsregeln zu schreiben) in Listing 2 kann man gut erkennen, dass die Ersetzungsregel rekursiv und so lange angewendet wird, bis ein Ausdruck nur noch ein Zahlsymbol ist. Für das Zahlsymbol sind keine Ersetzungsregeln definiert, es ist damit ein Terminalsymbol. Die Klammern in der BNF-Schreibweise definieren keine Präferenzregeln, eine Klammer stellt hier ein spezielles Token dar. Ähnlich einfach wie die Definition des Lexers ist die Definition des Parsers und seiner Grammatik.

Grammatik in Ruby-Code
class SimpleGrammar < Dhaka::Grammar  
	for_symbol(Dhaka::START_SYMBOL_NAME) {   start %w|  Expr | }
	for_symbol("Expr") do
			operation   %w| ( OPERATOR Expr Expr ) |
		integer     %w| n |
	end
end

Listing 3

Nachdem Lexer und Parser erstellt wurden, soll mit dem nächsten Schritt die Entwicklung der eigenen DSL vorangetrieben werden. Um das Ergebnis der Eingabe berechnen zu können, muss das Resultat der Analyse, der Parsebaum, ausgewertet werden. Die Dhaka-Evaluatorklasse wird nun zur Hilfe genommen, um den Parsebaum zu durchlaufen. Der Entwickler hat hierbei die Möglichkeit, an bestimmten Stellen Hooks in den Baum zu integrieren und so eigenen Code ausführen zu lassen.

Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Schreib den ersten Kommentar!

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.