Grammatik-Klasse

Grammatiken.rb — HTML, 23 kB (23.978 bytes)

Dateiinhalt

require "Warshall"
##
# Author::		Sebastian Bauer
# Author::		Alexander Jede
# Author::		Sergej Krun
# Author::		René Wickmann
# 
# Grammatiken
# ===========
#
# Dieses Programm liest einen Regelteil einer SIC-Grammatik ein,
# zerlegt ihn in seine Bestandteile und stellt einige Methoden 
# zur Verfügung um mit den so entstandenen Teilen zu arbeiten.

##
# Die Klasse Symb repräsentiert die Symbole einer Grammatik.
#
# Ihre Attribute sind:
# - @name -> die Bezeichnung des Symbols in der Grammatik als String
# - @terminal -> Boolean der angibt ob das Symbol ein Terminal ist
class Symb
  attr_accessor :terminal
	
	##
	# Konstruktor von Symb:
	# Setzt @name gleich dem übergebenen String und setzt @terminal standardmäßig auf True.
	#
	# Parameter:
	# - name -> Ein String, welcher das Symbol geschrieben darstellt.
	def initialize(name)
		@name = name
		@terminal = true
	end
	
	##
	# Getter für @name:
	def getName
		@name
	end
	
	##
	# to_s von Symb:
	#
	# Return:
	# -> @name
	def to_s
	  @name
	end

	##
	# == Operator von Symb
	#
	# Return:
	# -> True, wenn die @name-Attribute der Symbole = sind
	# -> False, wenn zweites Symbol nil ist, oder @name-Attribut nicht überinstimmt.
	def ==(anOther)
		if (anOther!=nil) then return (@name == anOther.getName) else return false end
	end
	
	##
	# <=> Operator von Symb
	#
	# Return:
	# -> 1 wenn das erste @name Attribut länger ist
	# -> 0 wenn beide gleichlang sind
	# -> -1 wenn das erste @name Attribut kleiner ist
	# -> false, wenn das zweite Symbol nil ist
	def <=>(anOther)
		if (anOther!=nil) then return (@name <=> anOther.getName) else return false end
	end
end

##
# Diese Klasse repräsentiert die einzelne Alternative auf der
# rechten Seite einer Regel. Sie besteht aus einem Array von 
# Symbolen.
#
# Ihre Attribute sind:
# - @symbs -> Das Array der Symbole (Positon nach ihrem Auftreten)
class Alternative

	##
	# Konstruktor von Alternative:
	#
	# Der Konstruktor zerlegt einen übergebenen String einer rechten
	# Seite einer Regel an den Leerstellen in Teilstrings. Diese
	# werden dem Konstruktor der Klasse Symb übergeben und die neuen
	# Symbole in das Array @symbs gesteckt.
	#
	# Parameter:
	# - alt -> Ein String einer Regelalternative (Standardwert = nil)
	def initialize(alt = nil)
		@symbs = Array.new
		# Nur wenn alt nicht nil ist müssen die Symbole abgelegt werden
		if alt != nil
			# Trennt den String an jeder Leerstelle
			alt.split(/\s+/).each { |symb|
				symb = symb.delete " "
				# Nur wenn der nun erkannte Teilstring nicht nur aus Leerzeichen bestanden hat wird ein 
				# neues Symbol mit dem Teilstring erstelt und im @symbs-Array abgelegt.
				if symb != ""
					@symbs.push(Symb.new(symb))
				end	
			}		
		end	
	end
	
	##
	# Getter für @symbs
	def getSymbols
		return @symbs
	end
	
	##
	# Gibt die Anzahl der Symbole im @symbs-Array zurück
	#
	# Return: Anzahl der Symbole in der Alternative
	def countSymbols
		return @symbs.size
	end
	
	##
	# [i] Operator von Alternative
	# 
	# Return: (i-1)tes Symbol der Alternative
	def [] (ind)
		return @symbs[ind]
	end
	
	##
	# <=> Oerator von Alternative
	#
	# Return:
	# -> 1 wenn die erste Alternative.to_s länger ist
	# -> 0 wenn beide gleichlang sind
	# -> -1 wenn die erste Alternative.to_s kleiner ist.
	# -> false, wenn die zweite Alternative nil ist
	def <=>(anOther)
		return (@symbs.to_s <=> anOther.getSymbols.to_s)
	end
	
	##
	# to_s von Alternative
	#
	# Return: Alle Symbole des @symb-Arrays mit to_s geschrieben und mit je einem Leerzeichen getrennt.
	def to_s
		res = String.new
		# Jedes Symbol aus @symbs an den String anfügen
		@symbs.each{ |symb| 
			res = res+" "+symb.to_s 
		}
		res
	end
	
	##
	# Prüft ob diese Alternative eine Epsilon-Alternative ist. Dies ist der Fall, wenn sie keine
	# Symbole enthält also @symbs leer ist.
	#
	# Return:
	# -> Boolean der Angibt ob es eine Epsilon-Alternative ist
  def isEpsilon
		@symbs.empty?
	end
end

##
# Diese Klasse repräsentiert die einzelnen Regeln. Jede Regel besteht aus 
# einem Symbol als linker Regelseite und einem Array mit Alternativen als 
# rechter Seite der Regel.
#
# Ihre Attribute sind:
# - @symbol -> Das Symbol der linken Regelseite
# - @alts -> Array aller Alternativen
class Rule
	
	##
	# Konstruktor von Rule:
	# Zerlegt eine als String in SIC-Format gegebene Regel in ihre Bestandteile und legt sie in den 
	# Attributen @symbol und @alts entsprechend ab.
	def initialize(rule)
		leftside, rightside = rule.split(/\s*->/)
		@symbol = Symb.new(leftside.strip)
		@symbol.terminal = false
		@alts = Array.new
		# Wenn auf der rechten Regelseite nichts steht wird eine Epsilon-Alternative angelegt.
		if rightside == nil
			@alts.push Alternative.new()
		# Ansonsten wird die rechte Seite an einem Zeilenumbruch, belibig vielen Blanks und "|" 
		# in die einzelnen Alternativen zerlegt und weiterbearbeitet
		else	
			# Für jede der so gefundenen Alternativen wird geprüft ob sie Epsilon-Alternativen sind.
			rightside.split(/\n\s*\|/).each { |a|
				# Wenn es keine Epsilon-Alternative ist wird eine neue Alternative erzeugt und in
				# @alts abgelegt.
				if (a.delete " ") != ""
					@alts.push Alternative.new(a)
				# Andernfals wird eine neue Epsilon-Alternative erzeugt und abgelegt.	
				else
					@alts.push Alternative.new(nil)
				end
			}
		end
	end
	
	##
	# Getter für @symbol
	def getSymbol
		return @symbol
	end
	
	##
	# Getter für @alts
	def getAlts
		return @alts
	end
	
	##
	# Gibt die Anzahl der Alternativen im @alts-Array zurück
	#
	# Return: Anzahl der Alternativen einer Regel
	def countAlts
		return @alts.size
	end
	
	##
	# [i] Operator von Rule
	# 
	# Return: (i-1)te Alternative der Regel
	def [] (ind)
		return @alts[ind]
	end
	
	##
	# to_s von Rule
	#
	# Return:
	# -> Die Regel im SIC-Format
	def to_s
	res = @symbol.to_s+" ->"
	# Jede Alternative an den String anfügen
	@alts.each_index{|i|
		# Wenn noch Alternativen folgen anfügen mit Zeilenumbruch und "|"
	  if i != @alts.length-1
	   res = res + " " + @alts[i].to_s + "\n   |"
	  # sonst nur anfügen der Alternative.to_s
		else
	   res = res + " " + @alts[i].to_s
	  end
	}
	res
	end
	
	##
	# Prüft ob aus einer Regel direkt(!) Epsilon abgeleitet werden kann (wenn entweder keine Alternativen
	# vorhanden sind oder eine dieser Alternativen eine Epsilon-Alternative ist).
	#
	# Return:
	# -> Boolean der angibt, ob eine direkte Epsilon-Ableitung möglich ist oder nicht.
	def isEpsilon
		# Wenn keine Alternativen vorhanden sind wird true zurückgegeben,
		if @alts.empty?
			return true
		# ansonsten muss jede Alternative einzeln geprüft werden.
		else
			@alts.each{ |alt|
				# Wenn die Alternative Epsilon-Alternative ist wird true zurückgegeben.
				if alt.isEpsilon
					return true
				end
			}
		end
		return false
	end

	
	##
	# Die Methode erzeugt Ausdrucksgrammatiken aus Kurzangaben.
	#  * Die Kurzangaben sind eine Folge von Zeilen, die jeweils ein Operatortoken  (z.B. addOp) in seinen Eigenschaften beschreiben.
	#  * Bei binären Operatortoken hat die Zeile den Aufbau:  <Assoc> <Operator>;
	#  <Assoc> steht für left, right oder none und legt die Assoziativität des
	#  Operators fest; none besagt, daß keine Assoziativität vorliegt und daher
	#  bei mehr als einem Operator voll geklammert werden muß.
	#  * Bei unären Operatortoken hat die Zeile den Aufbau: <Pos> <Operator>;
	#  <Pos> steht für pre oder post und legt fest, ob der Operator vor oder nach  dem Operanden steht.
	#  * Die Operatorzeilen sind nach wachsender Präzedenz angeordnet, d.h. 
	#  die  erste Zeile gehört zu dem Operatortoken, das am schwächsten bindet.
	#  * Die letzte Zeile hat die Form: atom <token 1 >, ..., <tokenN>
	#  und führt die atomaren Bestandteile des Ausdrucks ein.
	#  * Die erste Zeile hat die Form: name <Bezeichner>
	#  und führt den Namen der Ausdrucksgrammatik ein, mit dem alle erzeugten  Nonterminals beginnen.
	def Rule.from_Yacc(input)
		i = 1
		output = ""
		puts input + "\n"
		zeilen = input.split("\n")
		name = zeilen[0].split[1]
		# Erste Zeile
		output += name + " -> " + name + i.to_s + "\n"
		# Mittlere Zeilen
		zeilen.delete_at(0)
		zeilen.each do |zeile|
			optoken = zeile.split[0]
			operator = zeile.split[1]
			if optoken == "left"
				output += name + i.to_s + " -> " + name + i.to_s + " " + operator + " " + name + (i+1).to_s + "\n"
				output += " " * (name + i.to_s).length + " | " + name + (i+1).to_s + "\n"
				i += 1
			elsif optoken == "right"
				output += name + i.to_s + " -> " + name + (i+1).to_s + " " + operator + " " + name + i.to_s + "\n"
				output += " " * (name + i.to_s).length + " | " + name + (i+1).to_s + "\n"
				i += 1
			elsif optoken == "none"
				output += name + i.to_s + " -> " + name + (i+1).to_s + " " + operator + " " + name + (i+1).to_s + "\n"
				output += " " * (name + i.to_s).length + " | " + name + (i+1).to_s + "\n"
				i += 1
			elsif optoken == "pre"
				output += name + i.to_s + " -> " + operator + " " + name + i.to_s + " " + "\n"
				output += " " * (name + i.to_s).length + " | " + name + (i+1).to_s + "\n"
				i += 1
			elsif optoken == "post"
				output += name + i.to_s + " -> " + name + i.to_s + " " + operator + " " + name + (i+1).to_s + "\n"
				output += " " * (name + i.to_s).length + " | " + name + (i+1).to_s + "\n"
				i += 1
			end
		end
		# Letzte Zeile
		output += name + i.to_s + " -> " + "(" + name + 1.to_s + ")" +"\n"
		atome = zeilen[zeilen.size-1].split(/,\s|\s/)
		atome.delete_at(0)
		atome.each do |atom|
			output += " " * (name + i.to_s).length + " | " + atom + "\n"
		end
		puts output
	end
	
	##
	# liefert die Relation zu einer Regel
	def toRel
		links = @symbol 
		tmpMenge = Menge.new(getAlts)
		tmpRel = Relation.new([[]])
		tmpMenge.each{|i| i.getSymbols.each{|j| tmpRel.addPaar!(links.to_s, j.to_s )}}
	return tmpRel
	end

end
	
##
# Diese Klasse repräsentiert eine komplette Grammatik, mit Regeln, (Non-)Terminalsymbolen
# und einem Startsymbol.
#
# Ihre Attribute sind:
# - @rules -> Alle Regeln in einem Hash (Schlüßel ist das Symbol auf der Linken Seite)
# - @terminals -> Array aller terminalen Symbole
# - @nonterminals -> Array aller non-terminale Symbole
# - @startsymbol -> Das Startsymbol der Grammatik
# - @epsilonSymbole -> Menge aller Non-Terminal aus denen Epsilon abgeleitet werden kann
class Grammar
	
	# Der Konstruktor der Grammatik bekommt den Regelteil einer SIC-Grammatik
	# als String übergeb und spaltet ihn an einer Leerzeile in die einzelne
	# Regel, welche wiederum an den Konstruktor von Rule übergeben wird. Die
	# so entstehenden Regeln kommen in den @rules-Hash. Das Symbol der ersten
	# Regel wird das Startsymbol der Grammatik, alle anderen linksseitigen
	# Symbole sind die Non-Terminale. Die Terminale ergeben sich aus allen Symbolen
	# der zu allen Regeln gehörigen Alternativen die nicht vom Namen her mit
	# einem Non-Terminal übereinstimmen. 
	def initialize(gram)
		@rules = Hash.new
		@terminals = Array.new
		@nonterminals = Array.new
		gram.split(/\n\s*\n\s*/).each do |rule|
			newrule = Rule.new(rule)
			if @rules.size == 0
				@startsymbol = newrule.getSymbol
			end
			@rules[newrule.getSymbol] = newrule
			@nonterminals.push(newrule.getSymbol)
		end
		@rules.each_value  {|rule|
			rule.getAlts.each do |alt|
				alt.getSymbols.each do |symb|
					if @nonterminals.include?(symb) == false
						@terminals.push symb
					else
						symb.terminal = false
					end
				end
			end
		}
		@epsilonSymbole = epsilon_Symbole;
	end
	
	##
	# Getter für @startsymbol
	def getStartsymbol
		return @startsymbol
	end
	
	##
	# Getter für @terminals
	def getTerminals
		return @terminals
	end
	
	##
	# Getter für @nonterminals
	def getNonterminals
		return @nonterminals
	end
	
	##
	#Getter für @rules
	def getRules
		return @rules
	end
	##
	# Getter für @epsilonSymbole
	def getEpsilonSymb
		return @epsilonSymbole
	end
	
	##
	# Die to_s Methode liefert die Grammatik in einem String zurück.
	# Dabei steht jede Regel in einer Zeile und zwischen den Regeln ist eine Leerzeile.
	# Für das Format der Regeln, siehe Rule#to_s
	def to_s
	res = @rules[@startsymbol].to_s
	@rules.each_pair{|key,r|
	 if key != @startsymbol
	   res = res + "\n\n" +r.to_s
	 end
	}
	res
	end
	
	##
	# Liefert einen Array mit den Symbolen (Nonterminale), die Epsilon produzieren können.
	# 
	def epsilon_Symbole
		res = Menge.new([])
		# 1.Runde direkte Epsilon ableitungen finden
		@rules.each_pair {|name,rule|
				if rule.isEpsilon
					res.enthaelt?(name) ? () : (res.add(name))
				end
		}
		
		# 2. - x. Runde Suche nach indirekten Ableitungen
		neues = true
		while neues
			neues = false
			@rules.each_pair {|name,rule|
				rule.getAlts.each {|alt|
					nureps = true
					alt.getSymbols.each {|symb|
						res.enthaelt?(symb) ? () : (nureps = false)
					}
					nureps and !(res.enthaelt?(name)) ? (res.add(name);neues=true) : ()
				}
			}
		end
		
		return res
	end

	
	##
	# Diese Methode ermöglicht das Speichern der Grammatik in eine Datei.
	# Als Format wird YAML ( http://www.yaml.org/ ) benutzt, somit ist die Datei im Plaintext und kann auch mit einem
	# einfachem Editor bearbeitet werden. *Vorsicht*: Dabei kann man die Formatierung beschädigen, so dass
	# die gespeicherte Grammatik nicht mehr geladen werden kann.
	# file - Der Pfad zu der Datei in Form eines Strings, in der die Grammatik gespeichert werden soll.
	# Sollte die Datei nicht vorhanden sein, wird sie erstellt. <b> Ansonsten wird die Datei überschrieben! </b>
	def save(file)
	 require 'yaml'
	 gramma = Grammar.new(to_s)
	 File.open(file,"w"){|data|
	   YAML.dump(gramma,data)
	 }
	end
	
	##
	# Diese Methode ermöglicht es eine in einer Datei abgespeicherte Grammatik wieder zu laden.
	# Ein mögliches vorgehen wäre, in dem man eine leere Grammar erstellt und davon die Methode Grammar#load_grammar
	# aufruft. Zum Beispiel::
	#  g = Grammar.new("")
	#  g.load("/home/alex/SavedGrammar.yaml")
	# Grammar#load(file) - Der Pfad zu der Datei in Form eines String, in der die Grammatik gespeichert ist.
	#
	def load(file)
	 require 'yaml'
	 gramma = YAML::load(File.open(file))
	 if gramma.class == Grammar
	   @rules = gramma.getRules
	   @terminals = gramma.getTerminals
	   @nonterminals = gramma.getNonterminals
	   @startsymbol = gramma.getStartsymbol
		 @epsilonSymbole = gramma.getEpsilonSymb
	 else
	   #raise "Wrong File.\n It was not a Grammar"
	 end
	end
	
	##
	# Diese Methode stellt eine SIC-compatible Grammatik in Form eines Strings her.
	# Zu Beginn werden die terminalen Zeichen aufgelistet, gefolgt von den nichtterminalen Zeichen,
	# dem Startsymbol und zum Schluss den Ableitregeln.
	# Vor jedem Abschnitt leitet eine Überschrift die jeweiligen Zeichen ein, der noch eine zusätzliche 
	# Leerzeile folgt. 
	def to_SIC
	 res = "Terminals:\n\n"
	 getTerminals.each{ |termsym|
	   res += termsym.to_s + " "
	 }
	 res += "\n\nNonterminals:\n\n"
	 getNonterminals.each{ |nonterm|
	   res += nonterm.to_s + " " 
	 }
	 res += "\n\nStartingsymbol:\n\n" + getStartsymbol.to_s
	 res += "\n\nRules:\n\n" + to_s
	 return res	 
	end


	
	
	# liefert die Relation zu einer Grammatik
	def toRel
		erg = Relation.new([[]])
		getRules.each_key{|i| erg = erg.vereinigt(getRules[i].toRel)}
		return erg
	end
	
	# fügt eine Regel zur Grammatik hinzu
	def addRule(str)
		tempregel = str + self.to_s
		temp = Grammar.new(tempregel)
		return temp
	end

	
	
end


#Testfälle der Klasse Symb
require "test/unit"
class SymbToTest < Test::Unit::TestCase

	# Das Setup initialisiert zwei Symbole "s" und "T", wobei T noch als Non-Terminal gekennzeichnet wird.
	def setup
	   @symbol1 = Symb.new("s")
	   @symbol2 = Symb.new("T")
	   @symbol2.terminal=false
	   @symbol3 = Symb.new("s")
	end
	
	# Die Methode testet, ob die richtigen Namen der Symbole zurückgegeben werden.
	def test_getName
	   assert("s" == @symbol1.getName)
	   assert("T" == @symbol2.getName)
	end
	
	# Die Methode testet die String-Ausgabe der Symbole.
	def test_to_s
	   assert("T" == @symbol2.to_s)
	end
	
	# Die Methode testet den Attribut-Accessor.
	def test_attr_accessor
	   assert(@symbol1.terminal)
	   assert(!(@symbol2.terminal))
	end
	
	# Die Methode prüft, ob zwei Symbole anhand ihres Namens als gleich erkannt werden.
	def test_gleich
	   assert(@symbol1==(@symbol3))
	end
end

#Testfälle der Klasse Alternative
class AlternativeToTest < Test::Unit::TestCase
	
	# Es werden 3 Alternativen initialisiert und ein Symbol.
	def setup
	   @alternative1 = Alternative.new("H")
	   @alternative2 = Alternative.new("A B c")
	   @alternative3 = Alternative.new(" ")
	   @symbol3 = Symb.new("B")
	end
	
	# Die Methode prüft, ob alle Symbole einer Alternative erkannt wurden.
	def test_getSymbols
	   # to_s ist nötig, da die Adressen der beiden nicht übereinstimmen
	   assert("H" == @alternative1.getSymbols.to_s)
	   assert_equal("ABc", @alternative2.getSymbols.to_s)
	   assert_equal(@symbol3.to_s, @alternative2.getSymbols[1].to_s)
	end
	
	# Die Methode überprüft die Anzahl der vorkommenden Symbole in einer Alternative.
	def test_countSymbols
	   assert(1 == @alternative1.countSymbols)
	   assert(3 == @alternative2.countSymbols)
	   assert(0 == @alternative3.countSymbols)
	end
	
	# Die Methode testet, ob man durch Angabe des Indes auf ein Symbol zugreifen kann.
	def test_ind
	   assert_equal("H", @alternative1.[](0).to_s)
	   assert_equal("c", @alternative2.[](2).to_s)
	   assert_equal("", @alternative1.[](2).to_s)
	end
	
	# Die Methode testet die String-Ausgabe.
	def test_to_s
	   assert(" H" == @alternative1.to_s)
	   assert(" A B c" == @alternative2.to_s)
	end
	
	# Die Methode prüft, ob ein Symbol der 3 Alternativen ein Epsilonsymbol ist.
	def test_isEpsilon
	   assert(!(@alternative1.isEpsilon))
	   assert(!(@alternative2.isEpsilon))
	   assert(@alternative3.isEpsilon)     #ein Test in dem ein Epsilon dabei ist
	end
end

#Testfälle der Klasse Rule
class RuleToTest < Test::Unit::TestCase

	# Es werden 3 Regeln initialisiert: eine mit 2 Alternativen, eine mit einer und eine mit Epsilonproduktion.
	def setup
	   @regel1 = Rule.new("P -> g \n   |h") 
	   @regel2 = Rule.new("D -> p p")
	   @regel3 = Rule.new("B -> ")
	end
	
	# Die Methode prüft, ob das Non-Terminal auf der linken Seite zurückgegeben wird und ob es auch ein Non-Terminal ist.
	def test_getSymbol
	   assert_equal("P", @regel1.getSymbol.to_s)
	   assert(!(@regel1.getSymbol.terminal))  # mit "!", da die linke Regelseite ein Non-Terminal ist
	end
	
	# Die Methode testet, ob die richtigen Alternativen zurückgegeben werden, ob die Alternative bei @regel2 auch nur als eine Alternative erkannt wird
	# und ob es nach der einen erkannten Alternative auch keine weiteren mehr gibt.
	def test_getAlts
	   assert_equal(" g h", @regel1.getAlts.to_s)
	   assert_equal(" p p", @regel2.getAlts.to_s)
	   assert_equal(" p p", @regel2.getAlts[0].to_s)
	   assert_equal(nil, @regel2.getAlts[1])
	end
	
	# Die Methode testet, ob die richtige Anzahl an Alternativen zurückgegeben wird.
	# Bei @regel1 sind es zwei, bei @regel2 ist es eine und bei @regel3 ist es auch eine, nämlich das Epsilon.
	def test_countAlts
	   assert(2 == @regel1.countAlts)
	   assert(1 == @regel2.countAlts)
	   assert(1 == @regel3.countAlts)
	end
	
	# Die Methode prüft, ob man durch Angabe eines Index auf eine beliebige Alternative zugreifen kann.
	def test_ind
	   assert_equal(" h", @regel1.[](1).to_s)
	   assert_equal(" p p", @regel2.[](0).to_s)
	   assert_equal("", @regel3.[](0).to_s)
	end
	
	# Die Methode testet die gewünschte Ausgabe.
	def test_to_s
	   assert_equal("P ->  g\n   |  h", @regel1.to_s)
	   assert_equal("D ->  p p", @regel2.to_s)
	end
	
	# Die Methode prüft, ob die @regel1 und @regel2 kein Epsilon ist aber die @regel3 schon.
	def test_isEpsilon
	   assert(!(@regel1.isEpsilon))
	   assert(!(@regel2.isEpsilon))
	   assert(@regel3.isEpsilon)
	end
end

#Testfälle der Klasse Grammar
class GrammarToTest < Test::Unit::TestCase

	# Das Setup stellt initialisiert zwei Grammatiken.
	def setup
	   @grammatik1 = Grammar.new("P -> g \n   |h \n\nD -> p p")
	   @grammatik2 = Grammar.new("S -> H \n   |h \n\nH -> A \n   |B \n   |c \n\nA -> a \n   |b \n\nB -> ")
	end
	
	# Die Methode testet, ob das richtige Startsymbol zurückgegeben wird und ob es sich dabei um ein Non-Terminal handelt.
	def test_getStartsymbol
	   assert_equal("P",@grammatik1.getStartsymbol.to_s)
	   assert(!(@grammatik1.getStartsymbol.terminal))
	   assert_equal("S",@grammatik2.getStartsymbol.to_s)
	   assert(!(@grammatik2.getStartsymbol.terminal))
	end
	
	# Die Methode testet, ob alle Terminale aus der gegebenen Grammatik auch als Terminale erkannt wurden.
	def test_getTerminals
	   ablage1 = ablage2 = Array.new
	   @grammatik1.getTerminals.each_key do |schluessel|
		   ablage1 +=[schluessel]
	   end
	   assert_equal("pgh", ablage1.to_s)
	   
	   @grammatik2.getTerminals.each_key do |schluessel|
		   ablage2 +=[schluessel]
	   end
	   assert_equal("abch", ablage2.to_s)
	end
	
	# Die Methode testet, ob alle Non-Terminale aus der gegebenen Grammatik auch als Non-Terminale erkannt wurden.
	def test_getNonterminals
	   ablage1 = ablage2 = Array.new
	   @grammatik1.getNonterminals.each_key do |schluessel|
		   ablage1 +=[schluessel]
	   end
	   assert_equal("DP", ablage1.to_s)
	   
	   @grammatik2.getNonterminals.each_key do |schluessel|
		   ablage2 +=[schluessel]
	   end
	   assert_equal("ABHS", ablage2.to_s)
	end
	
	# Die Methode prüft, ob auch alle einzelnen Regeln erkannt wurden.
	def test_getRules
	   assert_equal("P ->  g\n   |  h", @grammatik1.getRules[@grammatik1.getStartsymbol].to_s)
	   assert_equal("D ->  p p", @grammatik1.getRules[@grammatik1.getNonterminals["D"]].to_s)
	   assert_equal("S ->  H\n   |  h", @grammatik2.getRules[@grammatik2.getStartsymbol].to_s)
	   assert_equal("H ->  A\n   |  B\n   |  c", @grammatik2.getRules[@grammatik2.getNonterminals["H"]].to_s)
	   assert_equal("A ->  a\n   |  b", @grammatik2.getRules[@grammatik2.getNonterminals["A"]].to_s)
	   assert_equal("B -> ", @grammatik2.getRules[@grammatik2.getNonterminals["B"]].to_s)
	end
	
	# Die Methode prüft, ob alle Symbole erkannt wurden, die Epsilon produzieren können.
	def test_epsilon_Symbole
	   assert_equal("",@grammatik1.epsilon_Symbole.to_s)
	   assert_equal(@grammatik2.getNonterminals["B"],@grammatik2.epsilon_Symbole[0])
	   assert_equal(@grammatik2.getNonterminals["H"],@grammatik2.epsilon_Symbole[1])
	   assert_equal(@grammatik2.getStartsymbol,@grammatik2.epsilon_Symbole[2])
	 
	end
	
	# Die Methode prüft, ob die Grammatik im gewünschten Format ausgegeben wird.
	def test_to_s
	   assert_equal("P ->  g\n   |  h\n\nD ->  p p", @grammatik1.to_s)
	end
	
	# Die Methode prüft, ob die Grammatik im gewünschten SIC-Format ausgegeben wird.
	def test_to_SIC
	  assert_equal("Terminals:\n\np g h \n\nNonterminals:\n\nD P \n\nStartingsymbol:\n\nP\n\nRules:\n\nP ->  g\n   |  h\n\nD ->  p p", @grammatik1.to_SIC)
	end
end
=begin
# Ausgabetest für die Klassenmethode Rule.from_Yacc
Rule.from_Yacc("name Arith\nleft addOp\nleft multOp\nright expOp\npre addOp\natom zahl, name\n")
Rule.from_Yacc("name L\nnone logBinOp\npre negOp\natom true, false, name\n")
gets
=end

@grammatik1 = Grammar.new("P -> g \n   |h \n\nD -> p p")
@grammatik2 = Grammar.new("S -> H \n   |h \n\nH -> A \n   |B \n   |c \n\nA -> a \n   |b \n\nB -> ")
puts @grammatik2.to_SIC
gets

inf2

Institut für Softwaretechnologie
Fakultät für Informatik
Universität der Bundeswehr München
85577 Neubiberg

Tel: +49 (89) 6004-2263 oder -3352
Fax: +49 (89) 6004-4447
E-Mail: inf2@unibw.de

So finden Sie uns

___

Hier finden Sie Informationen zum Studium an der Fakultät für Informatik

Der Studiendekan der Fakultät: Prof. Dr. Gunnar Teege