Baeume in Python

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Mittwoch 19. Oktober 2005, 13:33

Hi,
ich bins nochmal.
BlackJack hat geschrieben:PyParsing ist auch ganz nett um sich einen Parser für eigene "Spezialsprachen" zu basteln.

Edit: Hier ist ein Parser, der zumindest Dein Beispiel versteht:
[snip]
Die Struktur der Eingabedatei hat leider noch weitere Eigenschaften, so kann es z.B. sein, dass einer Variablen (Array) mehrere Werte, oder gar kein Wert zugewiesen werden koennen. Dies wuerde dann so aussehen:

Code: Alles auswählen

template T1 :=
{
   c1 := d1,
   b1 :=
   {
      b2 :=
      {
         a3 := 2,
         b3 := 3
      },
      a2 := 4
   },
   a1 := 5,
   a3 :=
   {
   	7,
      8,
      9
   },
   a4 := 
   {
      10
   },
   a5 :=
   {
   }
}
Ich versuche schon den ganzen Tag im vorhandenen Code "rumzubasteln", so dass der Parser das schluckt. Bisher leider ohne Erfolgsaussichten. Any hints?
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Donnerstag 20. Oktober 2005, 11:42

Hi,
der_Gerhard hat geschrieben: Ich versuche schon den ganzen Tag im vorhandenen Code "rumzubasteln", so dass der Parser das schluckt. Bisher leider ohne Erfolgsaussichten. Any hints?
ich habs hinbekommen, indem ich diese Zeilen hinzugefuegt/geaendert habe.

Code: Alles auswählen

array = Suppress('{') + ZeroOrMore(delimitedList(value)) + Suppress(ZeroOrMore('}'))
        item = Group(Optional(Suppress('{')) + key + Suppress(':=') + (value | body | array))
Konstrukte der Art

Code: Alles auswählen

template a:=
{
 a5:=
  {
      b:=5
   },
   {
      c:=6
   }
}
werden auch umgesetzt, aber leider in ['a', ['a5', ['b', '5']], ['c', '6']]. Korrekt waere
['a', ['a5', ['b', '5'], ['c', '6']]].
Sieht jemand den Fehler?

[edit] Au weia. Wo kein Fehler ist, kann auch niemand einen sehen.[/edit]

Hier nochmal die komplette Funktion;

Code: Alles auswählen

def makeGrammar(self):
        value = Word(alphanums + "_'()")
        value.setParseAction(lambda source, loc, toks: [toks[0]])
        key = Word(alphanums + "_")
        body = Forward()
        array = Suppress('{') + ZeroOrMore(delimitedList(value)) + Suppress(ZeroOrMore('}'))
        item = Group(Optional(Suppress('{')) + key + Suppress(':=') + (value | body | array))
        body << Suppress('{') + Optional(Suppress(ZeroOrMore('{'))) \
                + Dict(delimitedList(item)) + Suppress(ZeroOrMore('}'))
        template = Suppress(Keyword('template')) + item
        templates = Dict(OneOrMore(template)) + StringEnd()
        return templates
Edit (Leonidas): Code in Python-Tags gesetzt.
Zuletzt geändert von der_Gerhard am Freitag 21. Oktober 2005, 10:24, insgesamt 1-mal geändert.
BlackJack

Donnerstag 20. Oktober 2005, 21:29

der_Gerhard hat geschrieben:

Code: Alles auswählen

def makeGrammar(self):
        value = Word(alphanums + "_'()")
        value.setParseAction(lambda source, loc, toks: [toks[0]])
        key = Word(alphanums + "_")
        body = Forward()
        array = Suppress('{') + ZeroOrMore(delimitedList(value)) + Suppress(ZeroOrMore('}'))
        item = Group(Optional(Suppress('{')) + key + Suppress(':=') + (value | body | array))
        body << Suppress('{') + Optional(Suppress(ZeroOrMore('{'))) \
                + Dict(delimitedList(item)) + Suppress(ZeroOrMore('}'))
        template = Suppress(Keyword('template')) + item
        templates = Dict(OneOrMore(template)) + StringEnd()
        return templates
Die `parseAction` bei `value` bewirkt nichts, kann also wegfallen. Und die ganzen ``zeroOrMore('{')`` und auch die entsprechenden schliessenden Klammern machen die Grammatik ziemlich "komisch" und wohl auch uneindeutig. Die Klammern sind schliesslich da um einen Block oder eine Verschachtelungsebene zu identifizieren.

Ich fange mal von "oben" an aus der Grammatik einen möglichen Quelltext zu erstellen:

Code: Alles auswählen

"template" + item
"template {{{{{{{{{ " + delimitedList(item) + "}}}"
Das sieht an dieser Stelle schon ziemlich falsch aus.

Code: Alles auswählen

def make_grammar():
    value = Word(alphanums)
    identifier = Word(alphas, alphanums)
    body = Forward()
    assignement = Group(identifier + Suppress(':=') + (value | body))
    assignements = Dict(delimitedList(assignement))
    list_ = Group(delimitedList(value))
    body << Suppress('{') + (assignements | list_) + Suppress('}')
    template = Suppress(Keyword('template')) + assignement
    templates = Dict(OneOrMore(template)) + StringEnd()
    return templates
Versuch mal, ob das klappt. Eine Liste im Ergebnis erkennt man daran, das sie keine Zeichenkette ist und keine Schlüssel besitzt, also `len(x.keys()) == 0` gilt, wenn `x` das entsprechende `ParserResult` Objekt ist.

Die Grammatik ist nicht besonders schön, weil man mehr als ein Token vorausschauen muss um entscheiden zu können, ob man eine Liste oder ein weiteres "Dictionary" nach einem '{' hat.

Wo kommen die Daten denn her? Gibt's vielleicht eine offizielle Grammatik dafür?
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Freitag 21. Oktober 2005, 09:07

Hi BlackJack,
erst nochmals Danke fuer deine Bemuehungen; du scheinst meine letzte Hoffnung zu sein :-)
BlackJack hat geschrieben:Und die ganzen ``zeroOrMore('{')`` und auch die entsprechenden schliessenden Klammern machen die Grammatik ziemlich "komisch" und wohl auch uneindeutig. Die Klammern sind schliesslich da um einen Block oder eine Verschachtelungsebene zu identifizieren.
Dies war ein unschoener Versuch, mehrere sich oeffnende und schliessende Klammern parsen zu koennen (sieht man gleich im Beispiel).
BlackJack hat geschrieben:

Code: Alles auswählen

def make_grammar():
...[snip]
Versuch mal, ob das klappt. Eine Liste im Ergebnis erkennt man daran, das sie keine Zeichenkette ist und keine Schlüssel besitzt, also `len(x.keys()) == 0` gilt, wenn `x` das entsprechende `ParserResult` Objekt ist.
Also logisch ist die neue Funktion, aber der Interpreter meckert bei der ersten verschachtelten Zuweisung:
pyparsing.ParseException: Expected "}" (at char 205), (line:14, col:5): Dies ist am Ender der Anweisung b1:={...},
Die Grammatik ist nicht besonders schön, weil man mehr als ein Token vorausschauen muss um entscheiden zu können, ob man eine Liste oder ein weiteres "Dictionary" nach einem '{' hat.
Da muss ich dir recht geben, leider ist sie so festgeschrieben.
Wo kommen die Daten denn her? Gibt's vielleicht eine offizielle Grammatik dafür?
Die Daten sind in Dateien enthalten. Sie belegen Datenstrukturen mit speziellen Werten. Es kann aber davon ausgegangen werden, dass die Dateien syntaktisch korrekt sind, d.h. es waere auch egal, wenn eine falsche Klammerung in der Datei nicht vom Parser angemeckert wird, solange das erzeugte Dictionary bzw. Liste korrekt ist.
Nein, leider gibt es keine offizielle Grammatik. Ich gebe aber mal ein vollstaendiges Beispiel an, welches alle Sonderfaelle enthaelt.
Meine im letzten Post angegebene Funktion macht doch alles richtig, auch wenn sie nicht sauber programmiert ist, bis natuerlich auf die Parameterliste, aber die ist kommt spaeter.
Ich hatte wohl gestern nach ein paar Stunden Konzentration auf die Funktion nen Knick in der Optik.

Da aber die Templates spaeter auch wieder ausgegeben werden muessen, habe ich das Problem, dass ich wissen muss wieviele Klammer an jede Stelle gesetzt werden muessen, d.h. aus

Code: Alles auswählen

template a:=
{
 c0:=
 {
    {
       {
          b:=5
       }
    }
 }
}
wird ['a', ['c0', ['b', '5']]], woraus ich nicht mehr auf die Anzahl der Klammern schliessen kann. Also waere eine Moeglichkeit die Lieste folgendermassen aussehen zu lassen:
['a', ['c0', ['{', '{', 'b', '5', '}', '}']]] oder? Ich sehe da im Moment keine einfacher Moeglichkeit.

Code: Alles auswählen

template Typ1 name1 (Parameterliste z.B. template Typ2 name 2, template ... ) :=
{
   //Fall 1: Normale Zuweisung
   c1 := d1,
   //Fall 2: Normale verschachtelte Zuweisung
   b1 :=
   {
      b2 :=
      {
         a3 := 2,
         b3 := 3
      },
      a2 := 4
   },
   //Fall 3: Leere Liste
   a3 :=
   {
   },
   //Fall 4: Liste mit einem Element
   a4 := 
   {
      10
   },
   //Fall 5: Liste mit mehreren Elementen
   a5 :=
   {
      7,
      8,
      9   
   },
   //Sonderfall 1: Zuweisung(en) in geschweiften Klammern
   a6:=
   {
      a7:=
      {
         {
            a8 := 7,
            a9 := 8
         },
         {
            a10 := 99
         }
      }
   },
   //Sonderfall 2: mehrere Klammern
   a11:=
   {
      {
         {
            a12 := 42,
            a13 :=
            {
               a14 := 17   
            }
         }
      }
   }
}
Mann, mann mann. Ich dir auf jedenfall ein paar Bier schuldig, da du mir jetzt schon ein gutes Stueck weitergeholfen hast. Ich teste mal weiter und schreibe, wenn ich eine Loesung gefunden habe.

Gruss
Gerd
BlackJack

Samstag 22. Oktober 2005, 21:01

Okay ich bin jetzt bei folgendem gelandet:

Code: Alles auswählen

value = Word(alphanums).setResultsName('value')
identifier = Word(alphas, alphanums).setResultsName('identifier')
block = Forward()
assignment = Group(identifier + Suppress(':=')
                   + (value | block)).setResultsName('assignement')
assignments = Group(delimitedList(assignment)).setResultsName('assignments')
list_ = Group(Optional(delimitedList(value | block))).setResultsName('list')
block << Suppress('{') + (assignments | list_) + Suppress('}')
template_signature = identifier # TODO: Noch zu erweitern.
template = Group((Suppress(Keyword('template')) + template_signature
                 + Suppress(':=') + block)).setResultsName('template')
templates = OneOrMore(template).setResultsName('templates') + StringEnd()
templates.ignore(dblSlashComment)
Das parst zumindestend Dein Beispiel mit den Sonderfällen (inklusive Kommentaren).

Die `Dict()`s habe ich rausgeschmissen. Jetzt sind alles Listen/Sequenzen. Und ich habe den Untergrammatiken Namen gegeben, damit man zwischen 'assignments' und 'list' einfacher unterscheiden kann. Wirklich nötig sind nur 'assignments' und 'list' aber mit den anderen ist `result.asXML()` jetzt ganz nett lesbar.

Sonderfall 1 und 2 werden dadruch erschlagen, dass in Listen auch Blöcke erlaubt sind. In Deinem Sonderfall 1 ist `a7` dann eine Liste mit zwei Elementen, nämlich zwei Zuweisungsblöcke und im Sonderfall 2 is `a11` eine Liste, die eine Liste enthält, die wiederum einen Zuweisungsblock enthält.

Hier noch eine kleine Funktion, die aus einem Parser-Ergebnis wieder Quelltext erzeugt:

Code: Alles auswählen

def ast2str(ast):
    def template2str(template):
        name, body = template
        return ('template %s := ' % name) + node2str(body)
    
    def node2str(node):
        if isinstance(node, basestring):
            return node
        node_type = node.getName()
        if node_type == 'assignments':
            result = ', '.join('%s := %s' % (identifier, node2str(value))
                               for identifier, value in node)
        elif node_type == 'list':
            result = ', '.join(map(node2str, node))
        else:
            raise Exception('Unknown block type %r' % node_type)
        return '{ %s }' % result
    
    return '\n'.join(map(template2str, ast))
Da kommt eine Zeile pro Template heraus, also ohne hübsche Einrückung, aber man sieht hoffentlich ganz gut, wie man die Zuweisungsblöcke von den Listen unterscheiden kann und das keine Informationen verloren gegangen sind.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Montag 24. Oktober 2005, 14:20

Hi BlackJack,
BlackJack hat geschrieben:Okay ich bin jetzt bei folgendem gelandet:
Hier noch eine kleine Funktion, die aus einem Parser-Ergebnis wieder Quelltext erzeugt:

Code: Alles auswählen

def ast2str(ast):
    def template2str(template):
        name, body = template
        return ('template %s := ' % name) + node2str(body)
    
    def node2str(node):
        if isinstance(node, basestring):
            return node
        node_type = node.getName()
        if node_type == 'assignments':
            result = ', '.join('%s := %s' % (identifier, node2str(value))
                               for identifier, value in node)
        elif node_type == 'list':
            result = ', '.join(map(node2str, node))
        else:
            raise Exception('Unknown block type %r' % node_type)
        return '{ %s }' % result
    
    return '\n'.join(map(template2str, ast))
vielen Dank nochmals fuer deine Hilfsbereitschaft :D . Dein Code funktioniert super. Ich habe nur mit der 2ten Funktion Schwierigkeiten (Python Version 2.3.3). Der Interpreter meckert dort:
for identifier, value in node)
_^
SyntaxError: invalid syntax
Er mag die Schleife an dieser Stelle anscheinend nicht. Falls ich die betreffende Zeile aendere in

Code: Alles auswählen

for identifier, value in node:
    result = ', '.join('%s := %s' % (identifier, node2str(value)) )
was meinem Verstaendnis nach die Funktion an sich nicht veraendert, dann laeufts durch allerdings mit folgendem Ergebnis:

Code: Alles auswählen

 template Typ2 := { a, 1, 1,  , :, =,  , {,  , {,  , {,  , a, ,,  , 1, ,,  , 3, ,,  ,  , ,,  , :, ,,  , =, ,,  ,  , ,,  , {, ,,  ,  , ,,  , a, ,,  , ,, ,,  ,  , ,,  , 1, ,,  , ,, ,,  ,  , ,,  , 4, ,,  , ,, ,,  ,  , ,,  ,  , ,,  , ,, ,,  ,  , ,,  , :, ,,  , ,, ,,  ,  , ,,  , =, ,,  , ,, ,,  ,  , ,,  ,  , ,,  , ,, ,,  ,  , ,,  , 1, ,,  , ,, ,,  ,  , ,,  , 7, ,,  ,  , ,,  , },  , },  , },  , } }
Ich mach mich erst mal an die Erweiterung mit der Parameterliste.
Wie lange programmierst du eigentlich schon in Python?
Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 24. Oktober 2005, 14:56

der_Gerhard hat geschrieben:Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Und was daran ist mühselig?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Montag 24. Oktober 2005, 23:09

der_Gerhard hat geschrieben: vielen Dank nochmals fuer deine Hilfsbereitschaft :D . Dein Code funktioniert super. Ich habe nur mit der 2ten Funktion Schwierigkeiten (Python Version 2.3.3). Der Interpreter meckert dort:
for identifier, value in node)
_^
SyntaxError: invalid syntax
Er mag die Schleife an dieser Stelle anscheinend nicht. Falls ich die betreffende Zeile aendere in

Code: Alles auswählen

for identifier, value in node:
    result = ', '.join('%s := %s' % (identifier, node2str(value)) )
was meinem Verstaendnis nach die Funktion an sich nicht veraendert,
Doch das verändert die Funktion: Du weist `result` in jedem Schleifendurchlauf einen anderen, einzelnen Wert zu. Mach aus dem Generator Ausdruck in meinem Quelltext am besten eine `List Comprehension`, also innerhalb der runden Klammern des `join()` nochmal eckige um den Ausdruck:

Code: Alles auswählen

result = ', '.join(['%s := %s' % (identifier, node2str(value))
                     for identifier, value in node])
Wie lange programmierst du eigentlich schon in Python?
Ich bin 2003 auf Python gestossen als ich in Perl ein Problem lösen wollte, das verschachtelte Datenstrukturen zur Lösung benötigte.

Programmieren habe ich vor "Urzeiten" auf'm C64 angefangen. Damals noch BASIC und Assembler.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Dienstag 25. Oktober 2005, 08:07

Hi Leonidas,
Leonidas hat geschrieben:
der_Gerhard hat geschrieben:Im Moment finde ich den Einstieg in Python doch etwas muehselig, da ich es von C her gewohnt bin, mir die meisten Funktionen selbst zu programmieren. In Python hingegen geht dies auch, jedoch wenn man die Standardklassen und deren Funktionen kennt, scheint man diese nur noch kombinieren zu muessen und man loest das gleiche Problem mit einem Bruchteil an Quellcodezeilen.
Und was daran ist mühselig?
wenn ich mich dran mache und eine Funktion komplett selbst zu schreiben und mir anschliessend jemand eine Loesung praesentiert, die das gleiche mit 1/10 der Quellcodezeilen realisiert, dann ist das doch schon ziemlich deprimierend. Wenn man erst mal einen Ueberblick der Standardfunktionen hat, stelle ich es mir schon etwas einfacher vor.
Ich finde es im Moment muehselig, mir die ganzen Standardfunktionen anzueignen, was natuerlich zum Ergebnis fuehrt, dass man spaeter um so weniger Arbeit hat. Ich finde Python auf jeden Fall von Tag zu Tag besser.

Gruss
Gerhard
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Dienstag 25. Oktober 2005, 15:07

der_Gerhard hat geschrieben:wenn ich mich dran mache und eine Funktion komplett selbst zu schreiben und mir anschliessend jemand eine Loesung praesentiert, die das gleiche mit 1/10 der Quellcodezeilen realisiert, dann ist das doch schon ziemlich deprimierend.
Das passiert vielen Leuten. Auch mir passiert es manchmal, dass jemand das gleiche Problem wie ich sowohl kürzer als auch eleganter und leserlicher löst. Das ist aber Sache der Erfahrung (sowohl Erfahrung mit Python als auch Programmieren im allgemeinen).
der_Gerhard hat geschrieben:Wenn man erst mal einen Ueberblick der Standardfunktionen hat, stelle ich es mir schon etwas einfacher vor.
Du solltest dir vielleicht die, meiner Meinung nach exzellente, Python Quick Reference ansehen.
der_Gerhard hat geschrieben:Ich finde es im Moment muehselig, mir die ganzen Standardfunktionen anzueignen, was natuerlich zum Ergebnis fuehrt, dass man spaeter um so weniger Arbeit hat.
Ich finde es nicht so sehr sinnvoll auswendig zu lernen, welche Funktion was macht. Ich nutze lieber learning by doing: ein Beispiel: ich habe mal eine for-Schleife gebraucht, die sowohl durch eine Liste geht, als auch die Position der Liste. Deswegen habe ich im Forum hier gefragt und Dookie hat mir eine Lösung mit zip() gepostet. Monate später habe ich ein Snippet von BlackJack gesehen, welches genau das gleiche macht, jedoch mit enumerate(). Seitdem weiß ich, wenn ich sowas brauche: aha, es gibt die Funktion enumerate() zu dem Zweck.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Mittwoch 26. Oktober 2005, 15:22

Hi Black Jack,
BlackJack hat geschrieben:Okay ich bin jetzt bei folgendem gelandet:
[snip]
Hier noch eine kleine Funktion, die aus einem Parser-Ergebnis wieder Quelltext erzeugt:

Code: Alles auswählen

def ast2str(ast):
    def template2str(template):
        name, body = template
        return ('template %s := ' % name) + node2str(body)
[snip]
langsam wird es mir ein wenig peinlich, deine Hilfe wieder anzufordern, aber ich komme wiedermal nicht weiter:
Die template_signatur habe ich erweitert, was auch gut funktioniert hat.

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Da "name" jetzt aus mehreren Woertern besteht funktioniert die erste Zuweisung

Code: Alles auswählen

name, body = template
in der Funktion ast2str(ast) nicht mehr.
Ein Ansatz war bisher, das Ergebnis als Liste umzuwandeln und anschliessend ueber die einzelnen Signaturelemente zu laufen, etwa so:

Code: Alles auswählen

a = template.asList()
for i in range(0,len(erg[0]-2)):
b= a[0][i]
c= c.join(b)
Dieser Versuch war leider nicht sehr erfolgreich. Siehst du dort eine simple Loesung?
Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?

Gruss
Gerhard
BlackJack

Mittwoch 26. Oktober 2005, 22:57

der_Gerhard hat geschrieben: langsam wird es mir ein wenig peinlich, deine Hilfe wieder anzufordern, aber ich komme wiedermal nicht weiter:
Die template_signatur habe ich erweitert, was auch gut funktioniert hat.

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Da "name" jetzt aus mehreren Woertern besteht funktioniert die erste Zuweisung

Code: Alles auswählen

name, body = template
in der Funktion ast2str(ast) nicht mehr.
Erstmal eine Frage zur Grammatik der Signatur: Da folgen ja zwei Bezeichner aufeinander vor der Parameterliste: Das eine ist eine Typbezeichnung und das andere der Name des Templates? Warum ist einer dieser beiden Bezeichner denn Bestandteil der Parameterliste und der andere nicht?

Ansonsten: Wenn Du verschachtelte "Listen" als Ergebnis haben möchtest, dann macht man das mit `Group`. Wenn Du also ein `Group()` um die Signatur setzt, dann ist die gesamte Signatur im Ergebnis eine (Unter)Liste. Innerhalb der Signatur bietet es sich dann an, das mit der Parameterliste auch wieder zu tun um dann später in einer Schleife darüber laufen zu können.

Dann müsste es in der Funktion nicht mehr ``name, body = template`` heissen, sondern ``signature, body = template`` und danach dann eben entsprechender Quelltext, der die Signatur "auseinandernimmt". Also zum Beispiel die ersten beiden Elemente sind Typ und Templatename und dann folgt eine Liste mit Parametern. Die vielleicht wieder Listen mit zwei Elementen (Typ und Name) sind.
Ein Ansatz war bisher, das Ergebnis als Liste umzuwandeln und anschliessend ueber die einzelnen Signaturelemente zu laufen, etwa so:

Code: Alles auswählen

a = template.asList()
for i in range(0,len(erg[0]-2)):
b= a[0][i]
c= c.join(b)
Dieser Versuch war leider nicht sehr erfolgreich. Siehst du dort eine simple Loesung?
Wie gesagt, wenn man die Elemente in der Grammatik entsprechend gruppiert und verschachtelte Listen erstellt, dann sollte das lesbarer gehen. Das mit den Indices da oben versteht nach einem halben Jahr kein Mensch mehr auf Anhieb.
Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?
Ich hab jetzt keine genaue Vorstellung was da genau gemacht werden soll. Ich würde das Ergebnis vom Parsen vom Gefühl her aber auch eher als Zwischenergebnis ansehen und daraus dann eine Objekt aus verschiedenen Objekten/Klassen zusammenbauen, die dann die entsprechenden Funktionalitäten hätten, die ich bräuchte um damit zu arbeiten. Also zumindest wenn die Aufgabe nicht ganz trivial wäre und auf diesem "Abstract Syntax Tree" supereinfach zu erledigen wäre.
der_Gerhard
User
Beiträge: 14
Registriert: Mittwoch 21. September 2005, 09:06

Mittwoch 2. November 2005, 15:58

BlackJack hat geschrieben:
der_Gerhard hat geschrieben:

Code: Alles auswählen

parameter_list = identifier + '(' + delimitedList(Keyword('template') + 
                                          identifier + identifier) + ')'
template_signature = (identifier + 
                                         parameter_list).setResultsName('template_signature')
Erstmal eine Frage zur Grammatik der Signatur: Da folgen ja zwei Bezeichner aufeinander vor der Parameterliste: Das eine ist eine Typbezeichnung und das andere der Name des Templates? Warum ist einer dieser beiden Bezeichner denn Bestandteil der Parameterliste und der andere nicht?
Okay, das habe ich nicht richtig abgebildet. Den ersten identifier sollte man natuerlich mit zur Signatur nehmen. Also so:

parameter_list = '(' + delimitedList(Keyword('template') +
identifier + identifier) + ')'
template_signature = (identifier + identifier +
parameter_list).setResultsName('template_signature')

[snip: Gute Tipps]
BlackJack hat geschrieben:
der_Gerhard hat geschrieben:Zu was anderem: Da einzelne Templates spaeter miteinander verglichen werden muessen, ist es fur die Laufzeit von Vorteil, die Templates nach den Keys in jeder Ebene zu sortieren. Die Sortierfunktion fuer Listen ist da nicht geeignet, da sie mir auch die Schluessel-Wert Paare umsortiert, so dass spaeter nicht mehr erkennbar ist was jetzt Wert und was Schluessel ist. Gibt es dafuer andere sinnvolle Standardfunktionen?
Ich hab jetzt keine genaue Vorstellung was da genau gemacht werden soll. Ich würde das Ergebnis vom Parsen vom Gefühl her aber auch eher als Zwischenergebnis ansehen und daraus dann eine Objekt aus verschiedenen Objekten/Klassen zusammenbauen, die dann die entsprechenden Funktionalitäten hätten, die ich bräuchte um damit zu arbeiten. Also zumindest wenn die Aufgabe nicht ganz trivial wäre und auf diesem "Abstract Syntax Tree" supereinfach zu erledigen wäre.
Ich denke so einfach wird es (zumindest fuer mich) nicht.
Zunaechst muessen die Templates verglichen werde, d.h. es wird ein Basistemplate angegeben, welches mit allen anderen Templates in der Inputdatei verglichen wird. Das Ergebnis des Vergleichs ist die Anzahl der Key:=Value-Paaren, die in beiden Templates gleich sind. Ich denke fuer den Vergleich ist die Listendarstellung recht gut geeignet.

Darueber muss ich mir mal in den naechsten Tagen den Kopf zerbrechen.

Gruss
Gerhard
Gast

Mittwoch 23. November 2005, 15:32

der_Gerhard hat geschrieben: Zunaechst muessen die Templates verglichen werde, d.h. es wird ein Basistemplate angegeben, welches mit allen anderen Templates in der Inputdatei verglichen wird. Das Ergebnis des Vergleichs ist die Anzahl der Key:=Value-Paaren, die in beiden Templates gleich sind. Ich denke fuer den Vergleich ist die Listendarstellung recht gut geeignet.
Hi *,

mittlerweile bin ich zu dem Schluss gekommen, dass Listen fuer den Vergleich nicht gut sind, da sie schwer handbar sind. Ich mache dies mal an einem Beispiel klar:

Code: Alles auswählen

template name typ := {
          {
            a2 :=5,
            a1 :=
            {
              b1 :=
              {
                id := localTermId1
              }
            }
          },
          {
            a1 :=
            {
              b2 :=
              {
                id := localTermId2
              }
             },
          }
}
Um nun "id" eindeutig identifizieren zu koennen, muss man sich auch die ueberliegenden Strukturen merken, also id = a1->b1->id oder a1->b2->id. Dadurch ist id eindeutig ansprechbar, was mit der Listendarstellung nicht moeglich ist.
Kann mir jemand eine Hilfestellung geben, wie ich nun eine verschachtelte Liste mit key, value Paaren in ein verschachteltes Dictionary umwandle?
Ich habe probiert, dies mit Pyparsing und dictOf anstatt Group und delimitedList zu machen, allerdings ohne Erfolg.
BlackJack

Mittwoch 23. November 2005, 21:50

Ich kann mir immer noch nicht konkret vorstellen was Du mit den Templates anfängst. Ob es sich zum Beispiel lohnt über das Ergebnis vom Parser nochmal mit einer Funktion rüberzugehen, die eine Objekthierarchie aus den einzelnen Komponenten bastelt.

Oder eine andere Alternative wäre eine Funktion, die aus dem Parser-Ergebnis ein Dictionary aufbaut mit Einträgen wie:

{ 'a1.b1.id': localTermId1, 'a1.b2.id': localTermId2 }

Wobei ich jetzt nicht weiss: kann in beiden "Zuweisungslisten" auf der obersten Ebene auch die gleiche "Namenskette" auftauchen, also 2x 'a1.b2.id' die sich dann halt nur in der Position unterscheiden?
Antworten