next up previous contents
Next: 6.2.9 Transiente Regeln Up: 6.2 Eingabeanalyse Previous: 6.2.7 Spezielle Eingabeschlüsselworte

6.2.8 Gesamtfunktion

 

Im folgenden soll anhand der Regeln für die Eingabe von Linien gezeigt werden, wie die vorgestellten Einzelteile zusammenarbeiten.

Als erstes klinken wir das Nonterminal line-mode in das zentrale, wiederholt abgearbeitete Nonterminal main (Regel 6.8) ein:

;; hook line-mode rule to "main" nonterminal
(newrule
 "main"          ; the nonterminal derived by this rule
 NIL             ; no special test function
 '("line-mode")) ; the nonterminal deriving the rule

Für das Nonterminal line-mode gibt es nur eine Ableitung (Regel 6.7):

;; specify syntax and actions for accepting an arbitrary number of single lines
(newrule
 "line-mode"    ; the nonterminal derived by this rule
 NIL
 '(:LINE-MODE   ; the keyword triggering selection of this rule
   (ped::mode-switch (ped::actual-logical) ped::MODE-GEOMETRIC NIL)
                ; we want to see points, lines and faces - not segments etc.
   (mode "Enter single lines"
         ("first point" ":LINE (or (point %G) :IGNORE)")
         ("" "")
         ("" "")
         #'ped::elastic-point #'ped::elastic-point NIL NIL)
   NIL          ; here is the data collector for the loop - it's not used
   (:REPEAT     ; the loop specifier
    "line"      ; the only syntactic part of the loop is this nonterminal
    (mode "Enter single lines"
          ("first point" ":LINE (point %G)")
          ("" "")
          ("" "")
          #'ped::elastic-point #'ped::elastic-point NIL NIL)
    NIL)
   NIL))

Um diese Regel aktivieren zu können, wird ein Menüeintrag angelegt, der bei Auslösung das Schlüsselwort :LINE-MODE an den Parser schickt:

;; generate menu-entry for "line-mode"
(ped::register-selection
 "Edit"         ; the name of the menu
 "line"         ; the name and text of the menu entry
 #'ped::logical-command ; the function to be invoked on activation
 ":LINE-MODE\n")        ; the data to be passed to the function

Wenn der Parser auf eine Ableitung von main wartet und dieses Schlüsselwort erhält, prüft er, welche der Regeln es akzeptiert. Er wird die line-mode-Regel finden und aktivieren, worauf :LINE-MODE sofort akzeptiert wird. Die beiden nächsten Elemente der Regel sind Operationen, die sofort ausgeführt werden - erst die Umschaltung in den geometrischen Modus, dann die Konfiguration der Benutzerschnittstelle über mode. Uns interessiert hier ganz besonders die Zeichenkette für den linken Mausknopf:
":LINE (or (point %G) :IGNORE)"
Wenn der Anwender nun die Maus auf die Position mit den Weltkoordinaten (-1,0) bewegt und den linken Mausknopf drückt, dann wird dieser Text zuerst der Koordinatenersetzung unterzogen; deren Resultat ist
":LINE (or (point -1 0) :IGNORE)"
Die Funktion ped::logical-command macht daraus den LISP-Ausdruck
(:LINE (or (point -1 0) :IGNORE))
und ruft damit ped::eval-token-list auf. Diese Funktion zerlegt die Liste in ihre zwei Bestandteile und ruft für jeden ped::eval-token auf. Dort wird versucht, den jeweilige LISP-Ausdruck auszuwerten, und das Resultat wird über ped::apply-token an den Parser gesendet.

Das sieht in unserem Beispiel so aus: :LINE wertet auf sich selbst aus, wird daher unverändert weitergegeben. Der Parser wartet auf eine Möglichkeit, das Nonterminal line abzuleiten. Mit dem nun angekommenen Schlüsselwort aktiviert er daher die Regel 6.3. Diese akzeptiert nach dem Schlüsselwort zwei Punkte und ist - mit allen semantischen Regeln - so definiert:

;; specify syntax and actions for interactively creating a line
(newrule
 "line"                 ; the nonterminal solved by this rule
 NIL                    ; no explicit test function
 '(:LINE                ; this terminal-keyword in input-stream
                        ;    triggers this rule
   (mode "Enter first point of line"
         ("first point" "(or (point %G) :IGNORE)")
         ("first point" "(or (point %G) :IGNORE)")
         ("" "")
         #'ped::elastic-point #'ped::elastic-point NIL NIL)
   "point"              ; nonterminal to get first point - don't care how
                        ;    result has index 3
   (mode "Enter second point of line"
         ("second point" "(or (point %G) :IGNORE)")
         ("second point" "(or (point %G) :IGNORE)")
         ("cancel" ":CANCEL")
         #'ped::elastic-line #'ped::elastic-line ($ 3) NIL)
   "point"              ; nonterminal to get second point - don't care how
                        ;    result has index 5
   (line ($ 3) ($ 5))   ; access results of point nonterminals by
                        ;    $-Function with appropriate indices and
                        ;    generate the line from the two points
))

Das Schlüsselwort :LINE wird sofort akzeptiert, der Modus neu konfiguriert (was sich aber in der Anzeige nicht auswirkt), und ein Punkt erwartet. Dieser wird sofort nachgeliefert als zweites Wort, das durch den Mausknopf gesendet wurde:
(or (point -1 0) :IGNORE)
ped::eval-token wertet diesen Ausdruck schließlich aus. Wenn die point-Funktion erfolgreich war (was im zweidimensionalen Fall zu erwarten ist), dann ist das Ergebnis ein CLS-Punkt. Der Parser akzeptiert ihn aufgrund der Regel 6.4, legt ihn auf den Datenstapel und führt die zweite mode-Funktion der line-Regel aus. Da keine weiteren Worte mehr bereitstehen, kehrt der PED, nachdem er die neue Konfiguration realisiert hat, in seine Warteschleife zurück.

Dem Benutzer präsentiert sich daher, wenn er nun die Maus bewegt, etwa das Bild nach Abb. 6.5. Eine Linie wird nun ständig zwischen dem ersten Punkt und dem Mauszeiger geführt. Die interne Konfiguration des linken Mausknopfes ist jetzt
"(or (point %G) :IGNORE)"

Wenn der Benutzer wiederum den linken Mausknopf drückt, dann wird ähnlich wie beim ersten Mal der Punkt generiert und an den Parser geschickt. Dieser akzeptiert ihn, legt in auf den Datenstapel, und führt gemäß der Regel den Ausdruck (line ($ 3) ($ 5)) aus. ($ 3) wird durch das Resultat des dritten Elementes, also den ersten Punkt, ersetzt, und ($ 5) durch den zweiten. Es bleibt also der Aufruf der Funktion line mit den beiden Punkten als Parameter - das Ergebnis ist die gewünschte Linie, die zwar hier nicht mehr benötigt wird, aber als Seiteneffekt generiert wurde.

Regel 6.3 ist damit erledigt, und wir stehen wieder in der Bearbeitung von line-mode.

   figure2261
Abbildung 6.5: Sichtbare Konfiguration des PED während Ausführung der Regel line

Einen Punkt in zweidimensionalen Geometrien erhält man, wie gerade gezeigt, mit
"(point %G)". Während der Vorverarbeitung erfolgt der Funktionsaufruf (point 1.2 3.4), der einen Punkt an dieser Position liefert.

Eine andere interessante Art der Vorverarbeitung geschieht mit Funktionen zum Einfangen (snap) vorhandener Daten. "(snap-line %g)" versucht mit den resultierenden Koordinaten eine Linie zu finden. Wenn die Funktion entsprechend definiert ist, funktioniert dies in beliebig dimensionalen Räumen.

Funktionen zum Einfangen liefern in dem Fall, daß kein Objekt getroffen wurde, NIL. Um zu verhindern, daß der Parser in diesem Fall Fehler erkennt oder diesen Wert als gültig ansieht und die Regel weiter abarbeitet, kann auf das Schlüsselwort :IGNORE ausgewichen werden, damit der Benutzer die Eingabe wiederholen kann.
"(or (snap-line %g) :IGNORE)" ist eine entsprechende Konfiguration.


next up previous contents
Next: 6.2.9 Transiente Regeln Up: 6.2 Eingabeanalyse Previous: 6.2.7 Spezielle Eingabeschlüsselworte

Martin Knaipp
Wed Jun 12 15:41:33 MET DST 1996