MB: Tokenizer Entwurf und Ansätze in Proprietärer Skript-Sprache ok?

moin,

Zu MB: Strukturierter Klartext zu Array mit Compiler oder Präprozessor??? will ich einen Tokenizer in einer proprietären Skriptsprache entwickeln ohne Regular Expressions. Beim Entwurf waren mir vorab Probleme bewusst, die ich hier anführen werde. Gegeben ist ein string was ein multidimensionales hashmap beschreibt:

Legende
Zur Veranschaulichung:

  • . ist ein Leerzeichen
  • ---> ist ein Tabulator
  • <end> ist ein Zeilenumbruch kein Zeilenende
:ARRAY--->--->--->--->- this is an array<end>
..0:STRING--->--->--->- this is a string<end>
..1:ARRAY>--->--->--->- this is an array<end>
....0:STRING->--->--->- this is a string<end>
....1:CODE--->--->--->- this is a code<end>

Ich will mit non-context-free die Einrückungen und mit context-free die Variablen Argumente mit dem zugehörigen Text arbeiten.

Die liste soll [ STRING, [ STRING, CODE ] ] ausdrücken.

rauskommen soll dann:

[
  [[0],[],['ARRAY'],["this is an array"]],
  [[1],[0],['STRING'],["this is a string"]],
  [[1],[1],['ARRAY'],["this is an array"]],
  [[2],[0],["STRING"],["this is a string"]],
  [[2],[1],["CODE"],["this is a code"]]
]

Es ist gleich ob einen chaotische Indentations-Rangfolge entsteht. Es kann auch so aussehen:

....10...:.ABCD--->- text text text<end>
..:FGH->--->--->--->---><end>
--->--->- text text<end>
......3<end>
:<end>
GHIJ<end>
--->- text

rauskommen soll dann:

[
  [[2],[10],['ABCD'],["text text text"]],
  [[1],[],['FGH'],["text text"]],
  [[3],[3]['GHIJ'],["text"]]
]

Der Indikator soll nur sein:

  1. non-context-free: [space(s)]
  2. context-free: [index][":"][Capital(s)][tab(s)]["- "][string]

Ich hab derweil Makro Funktionen entwickelt die Regular Expressions zum geringen teil ersetzen.

Wäre meine Überlegung ok oder ist es sinnvoller das ich diese verwerfe?

lgmb

--
Sprachstörung
  1. Hallo MB,

    ich gebe mir Mühe, Dir zu folgen, bin aber nicht ganz sicher, ob das gelingt.

    Deine Eingabe besteht also aus Informationsbrocken, von denen jeder zu einem Hashmap-Eintrag werden soll.

    Ein Informationsbrocken kann eingerückt sein, die Einrückung soll erfasst werden.

    Der eigentliche Inhalt besteht aus einer Zahl, * einem Doppelpunkt, * einem Schlüsselwort in Großbuchstaben, Tabs, * Tabs, ein Minuszeichen, mutmaßlich gefolgt von einer Leerstelle, und dann beliebigem Text.

    Überall wo ich ein Sternchen gemacht habe kann auch ein Zeilenumbruch sein, der überlesen werden soll.

    Die Zahl kann fehlen.

    Was kann noch fehlen? In deiner Beschreibung ist jede Teilkomponente in eckige Klammern gesetzt, diese stehen in Syntax-Notationen zumeist für „optional“

    Kann der "beliebige Text" ebenfalls von einem Zeilenumbruch unterbrochen werden?

    Wenn nicht, ist das Ende eines Informationsbrockens klar definiert. Wenn ja: Woran erkennst Du den Beginn des nächsten Informationsbrockens? An der Zahl? Darf der Text demzufolge keine Zahlen enthalten? Oder am Doppelpunkt? Darf der Text demzufolge keinen Doppelpunkt enthalten?

    Rolf

    --
    sumpsi - posui - obstruxi
    1. moin,

      ich gebe mir Mühe, Dir zu folgen, bin aber nicht ganz sicher, ob das gelingt.

      tut mir leid :/

      Der eigentliche Inhalt besteht aus einer Zahl, […]

      ein Index soweit richtig.

      Was kann noch fehlen? In deiner Beschreibung ist jede Teilkomponente in eckige Klammern gesetzt, diese stehen in Syntax-Notationen zumeist für „optional“

      Ja, ich bin leider nicht Firm in RegEx sry, sonst könnte ich mich durch sie besser ausdrücken daher die Legende och versuche es aber dennoch.

      Kann der "beliebige Text" ebenfalls von einem Zeilenumbruch unterbrochen werden?

      das habe ich nicht im Beispiel erwähnt ja kann er.

      Wenn nicht, ist das Ende eines Informationsbrockens klar definiert. Wenn ja: Woran erkennst Du den Beginn des nächsten Informationsbrockens? An der Zahl? Darf der Text demzufolge keine Zahlen enthalten? Oder am Doppelpunkt? Darf der Text demzufolge keinen Doppelpunkt enthalten?

      Zunächst an der Kombination:
      Index, Doppelpunkt, Kapitalschrift, Tabulator(en), "- ", String.

      Mir drängt sich folgende Fragen auf:

      • sind String-Kombinationen ein eingesetztes Technisches Werkzeug für Token Erstellung?
      1. Ist es besser verschachtelter vorzugehen

        • TOKEN_PARAMETER: Indikator für [0-9]*\:[A-Z]
        • TOKEN_DESCRIPTION: Indikator für (- )[\w\n ]*
          Bedarf es dann eines LEXERs wenn man z.B TOKEN_PARAMETER noch in TOKEN_INDEX, TOKEN_SEPARATOR, TOKEN_TYPE unterteilt?
      2. oder weitest gehend ohne Gruppierung und autonom:

        • TOKEN_INDEX, TOKEN_SEPARATOR, TOKEN_TYPE, TOKEN_POINT, TOKEN_TEXT

      P.S.: Nochmal danke ich Dir Recht herzlich für deine Hilfe! Ich weis es wirklich sehr zu schätzen.

      P.S.S.: das ist seeehr neu für mich einen simplen Tokenizer für einen Parse zu schreiben. Bitte entschuldigt

      lgmb

      --
      Sprachstörung
      1. Hallo MB,

        es ist wirklich sehr schwierig, deinen Gedankengängen zu folgen. Mir scheint auch, dass Du keine Vorstellung hast, welcher Systematik Du folgen willst.

        Ich fragte:

        Woran erkennst Du den Beginn des nächsten Informationsbrockens?

        Du sagst:

        Zunächst an der Kombination: Index, Doppelpunkt, Kapitalschrift, Tabulator(en), "- ", String.

        DAS ist eine sehr komplexe Idee. Du bist im Informationsbrocken 1 bis zum String gelangt. Nun musst Du alles folgende, was Du findest, als Teil dieses Strings auffassen, bis Du den Beginn des nächsten Informationsbrockens erkennst. Und das kann beliebig komplex werden. Ich möchte Dir mit Leitfragen helfen.

        Die Indexnummer ist optional. Der Doppelpunkt auch? Oder eher nicht? Was ist mit der Kapitalschrift? Pflicht oder optional? Das fragte ich bereits, aber Du hast es nicht beantwortet.

        Was auch wichtig wäre: Darf es sein, dass der String von Block 1 endet und der Block 2 auf der gleichen Zeile beginnt? Oder beginnt ein Informationsblock grundsätzlich auf einer neuen Zeile?

        Von den Antworten auf diese Fragen hängt es ab, wie sehr dein Parser raten muss. Aber ein wenig raten muss er auf jeden Fall, weil dein "string" Teil kein klar definiertes Ende hat. Es gibt Stellen, wo nicht klar ist, ob ein angetroffenes Zeichen zum String des vorigen Blocks gehört, oder einen neuen Block beginnt.

        Man nennt das ein Entscheidungsproblem. Das Programm muss entscheiden, ob es links- oder rechtsrum laufen muss, aber hat noch nicht genug Daten um die Entscheidung treffen zu können. Zur Lösung gibt es mehrere Strategien (entnommen aus: Jackson Structured Programming - das war Stoff meiner Berufsausbildung...)

        • Do/Undo: Einfachste Form. Man entscheidet sich für eine Seite und schreitet wacker voran. Stellt man fest, dass man auf der falschen Seite ist, muss man alles, was auf der falschen Seite passiert ist, rückgängig machen und auf der richtigen Seite einsteigen. Hat man z.B. irgendwo "+1" gerechnet, muss man im Undo "-1" rechnen.

        • Note/Restore: Wenn Do/Undo zu komplex wird: Man merkt sich den Ausgangszustand, legt auf einer Seite los und wenn man falsch lag, setzt man die Daten auf den gemerkten Zustand zurück.

        • Pretend/Really Do: Wenn ein Undo oder Restore nicht möglich ist (z.B. weil zum "do" das Löschen einer Datei oder das Senden einer Mail gehörte): Man führt die eigentlichen Aktionen nur soweit wie nötig/möglich aus, dass ein Undo oder Restore noch möglich ist. Erst, wenn klar ist, dass man auf der richtigen Seite ist, werden die unwiderrufbaren Teile ausgeführt.

        • Backtracking: Wenn das Entscheidungsproblem sich zu einem Entscheidungsbaum auswächst, und Du nicht weißt, in welchen Ast Du musst. Dann kann es passieren, dass Du mehrere Prüfpunkte hast und Dich im Irrtumsfalls schrittweise zurückarbeiten musst. Das Damenproblem ist ein Beispiel dafür.

        Das war jetzt ein Exkurs; in deinem Fall ist es nicht ganz so komplex. Aber ein Entscheidungsproblem hast Du auf jeden Fall zu lösen. Wenn Du an einer Stelle, wo ein Block beginnen kann, auf Daten triffst, die zu einem Blockbeginn passen, dann muss dein Parser diese Möglichkeit einbeziehen. Und Du musst eine Strategie finden, wie das erfolgen soll.

        Diese Strategie muss auf jeden Fall eins können: den Punkt finden, wo die Spekulation endet. Sie endet entweder mit der Erkenntnis, dass man im falschen Entscheidungsast war, oder mit der Entscheidung, im richtigen Ast zu sein. Je nach gewählter Vorgehensweise folgen dann die Aktivitäten, um die Spekulation aufzulösen.

        Das ist nicht einfach. Die Entscheidung, wie Du das machen willst, musst Du treffen. Was am einfachsten ist, hängt auch davon ab, wie einfach Du im Eingabedatenstrom wieder zurück kannst. Das kann ich nicht beurteilen, ich kenne SQF nicht.

        Rolf

        --
        sumpsi - posui - obstruxi
  2. Datei test.yaml:

    foo: [1,2]
    bar: ["Hallo", "Welt"]
    tok:
         - "Oh!"
         - "Ha!"
    tik: 100.01
    tak: "Hallo Welt"
    arr:
            FOO: valueFoo
            BAR: valueBAR
    arrdeep:
            FOOdeep: [1,2,3]
            BARdeep:
                    - "Ein Dieb in der Bar"
                    - "Bargeld lacht"
    

    Datei test.php

    <?php
    $ndocs = 0;
    $data = yaml_parse_file("test.yaml", 0, $ndocs, array());
    var_dump($data);
    

    Ausgabe:

    array(7) {
      ["foo"]=>
      array(2) {
        [0]=>
        int(1)
        [1]=>
        int(2)
      }
      ["bar"]=>
      array(2) {
        [0]=>
        string(5) "Hallo"
        [1]=>
        string(4) "Welt"
      }
      ["tok"]=>
      array(2) {
        [0]=>
        string(3) "Oh!"
        [1]=>
        string(3) "Ha!"
      }
      ["tik"]=>
      float(100.01)
      ["tak"]=>
      string(10) "Hallo Welt"
      ["arr"]=>
      array(2) {
        ["FOO"]=>
        string(8) "valueFoo"
        ["BAR"]=>
        string(8) "valueBAR"
      }
      ["arrdeep"]=>
      array(2) {
        ["FOOdeep"]=>
        array(3) {
          [0]=>
          int(1)
          [1]=>
          int(2)
          [2]=>
          int(3)
        }
        ["BARdeep"]=>
        array(2) {
          [0]=>
          string(19) "Ein Dieb in der Bar"
          [1]=>
          string(13) "Bargeld lacht"
        }
      }
    }
    
    

    Das ist so einfach (auch die Syntax von YAML) - da stellt sich die Frage, warum Du was eigenes erfinden willst, sehr ernsthaft. Oder geht es gar nicht um die Lösung des Problems an sich?

    1. moin,

      Das ist so einfach (auch die Syntax von YAML) - da stellt sich die Frage, warum Du was eigenes erfinden willst, sehr ernsthaft. Oder geht es gar nicht um die Lösung des Problems an sich?

      Erst einmal herzlichen Dank für das gucken über den Tellerrand 😉. SQF wie ich hier beschrib ist eine proprietäre isolierte Skript Sprache.

      Werde ich mir ansehen. Ich möchte das Rad nicht neu erfinden um beruflich zu entwickeln. Meine Intension ist, selber machen um zum lernen. Im aktuellen Fall geht es einfach nicht. Und ich hab einen miserablen Parser schon geschrieben.

      Ein Problem ist, das die BIS Entwickler fantasievolle Format in mehrzeiligen Skript Kommentar erstellen.

      /***** und *****/, order einfach /* und */, oder mit und ohne Header:, dann ====== als <hr />, dann name: oder file: was das gleiche bedeutet, mit oder ohne Zeileneinrückungen, Groß und Kleinschreibung. Schon sehr abenteulerlich. Die BIS Entwickler können sich einfach nicht einigen, welchen Standard sie haben wollen, habe ich das Gefühl.

      Daher habe ich einen Standard erzeugt das die meisten Entwickler verwenden mit variablen Tokens

      lgmb

      --
      Sprachstörung
      1. Ein Problem ist, das die BIS Entwickler fantasievolle Format in mehrzeiligen Skript Kommentar erstellen.

        /***** und *****/, order einfach /* und */, oder mit und ohne Header:, dann ====== als <hr />, dann name: oder file: was das gleiche bedeutet, mit oder ohne Zeileneinrückungen, Groß und Kleinschreibung. Schon sehr abenteulerlich. Die BIS Entwickler können sich einfach nicht einigen, welchen Standard sie haben wollen, habe ich das Gefühl.

        Was sind denn „BIS Entwickler“ und in welchem Verhältnis stehst Du zu diesen? Und wieso können sich „Entwickler“ nicht auf eine vernünftige Lösung und also Format-Vorschriften einigen?

        Wieso soll dann an ein anderer etwas programmieren, was deren „Zeichensalat“ erkennt - also künstliche Intelligenz erfordert und dann trotzdem (oder: deshalb) keine eindeutigen Ergebnisse bringen kann?

        Ist schönes Wetter. Ich geh jetzt raus.

        1. moin,

          Ein Problem ist, das die BIS Entwickler fantasievolle Format in mehrzeiligen Skript Kommentar erstellen.

          Was sind denn „BIS Entwickler“ und in welchem Verhältnis stehst Du zu diesen? […]

          Ich war und bin eben ein Fan von einem Produkt von BIS wie ich schon erwähnt habe. Sie sind damals mehr "Code offener" und aktuell stellen sie deren gesamte Software Entwicklung für ihr Produkt zur Verfügung. Für mich ein riesen großer Pluspunkt.

          […] Und wieso können sich „Entwickler“ nicht auf eine vernünftige Lösung und also Format-Vorschriften einigen?

          Eine Sehr gute Frage die du besser BIS stellen solltest und nicht mir 😉. Ich glaube manche von den BIS Skriptern sind all-around Angestellte die weniger coden und mehr andere Dinge für die Firma tun, z.B. Objekt designen usw. Manche schreiben überhaupt keinen Kommentare in ihren Code. Ich kann mir das so erklären das sie für ihre Skript-Funktionalität systemperformanter gearbeitet haben was ich ja zum Teil auch tue. z.B.:

          systemperfomanter:

          _this select 0 isEqualTo _this select 1 or {_this select 0 isEqualTo _this select 2}
          

          strukturvoller:

          // ---- DECLARATION
          _this params [
            [ "_input", 0, [ 0 ] ],
            [ "_foo", 0, [ 0 ] ],
            [ "_bar", 0, [ 0 ] ]
          ];
          
          [] params [
            [ "_result", false, [ false ] ]
          ];
          
          // ---- PROCESS
          // switch
          _result = switch ( _input ) do {
            
            // foo
            case _foo : {
              true
            };
            // bar
            case _bar : {
              true
            };
          
            // default
            default {
              false
            };
          };
          
          // ---- RETURN
          _result
          

          in beiden fantasie Fällen käme das gleiche heraus aber in unteren Fall hat man sehr viel mehr Infos für den weiteren Programmverlauf.

          Wieso soll dann an ein anderer etwas programmieren, was deren „Zeichensalat“ erkennt - also künstliche Intelligenz erfordert und dann trotzdem (oder: deshalb) keine eindeutigen Ergebnisse bringen kann?

          es geht mir nur um die Kommentare. Ich will sonne Art Amateur SQFDoc entwickeln was PHPDoc, JavaDoc oder JSDoc schon nutzen. Komischerweise hat das noch keiner gemacht 😕.

          Ist schönes Wetter. Ich geh jetzt raus.

          Grüß mir die Sonne 😉

          lgmb

          --
          Sprachstörung
          1. moin,

            whou, kann kramdown ja auch SQF 😀???

            lgmb

            --
            Sprachstörung
      2. Hallo,

        Ich möchte das Rad nicht neu erfinden um beruflich zu entwickeln.

        eine gute und vernünftige Einstellung, aber man sollte von Fall zu Fall abwägen. Denn manche Räder, die es fertig gibt, brauchen viel Nachbearbeitung, bis sie zum eigenen Projekt passen.

        Ich versuche daher meistens, vorher abzuschätzen, wie lange ich selbst in etwa brauchen würde, um die nötige Funktionalität umzusetzen. Das kann natürlich nur eine ganz grobe Schätzung sein. Dann schaue ich mich nach bereits existierenden Lösungen um, vergleiche sie mit meinen Anforderungen, lese die Doku dazu mal kurz an.

        Oft stelle ich dann fest: Die fertige Lösung kann viel mehr, als ich eigentlich brauche, erfordert aber auch viel Aufwand, um sie zu integrieren. Das ist dann ein Argument fürs Selbermachen. Ein anderer könnte der Lerneffekt sein, den du auch schon angesprochen hast. Oder sehr spezielle Details der Implementierung, die kein fertiges Rad out of the box mitbringt. Wenn ich also sowieso schon fremden Code analysieren und erweitern müsste ... nö, dann lieber gleich selbermachen.

        Daher habe ich einen Standard erzeugt das die meisten Entwickler verwenden mit variablen Tokens

        Das wäre also mein Szenario: Sehr spezielle Anforderungen, die keine fertige Tütensuppe erfüllt.

        Live long and pros healthy,
         Martin

        --
        Lasst uns ins Horn brechen und aufstoßen. Höchste Zeit, auf den Weg zu machen.
        (mit freundlichem Dank an Tabellenkalk für die Ergänzung 😀)
        1. moin,

          Ich möchte das Rad nicht neu erfinden um beruflich zu entwickeln.

          eine gute und vernünftige Einstellung, aber man sollte von Fall zu Fall abwägen. Denn manche Räder, die es fertig gibt, brauchen viel Nachbearbeitung, bis sie zum eigenen Projekt passen.

          Das sehe ich absolut genau so alles was du sagst 😉. Dann habe ich nicht viel Falsch gemacht 😀.

          lgmb

          --
          Sprachstörung