home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / spezial / 02 / texte / pascomp.3 < prev    next >
Encoding:
Text File  |  1980-01-03  |  32.3 KB  |  801 lines

  1. Pascomp
  2. Pascal baut einen Pascal-Compiler
  3.  
  4.  
  5. Teil 4: Der Parser
  6.         VON JOHANNES VELMANS
  7.  
  8. In  der  vierten Folge der Serie "Pascal baut einen PASCAL-Compi-
  9. ler"  geht es rund um die Zerteilung (Parsing). Die ersten beiden
  10. Kapitel  vermittelten einen Einblick in die Grundlagen des Compi-
  11. lerbaus  und  zeigten  auch,  was der Mensch so alles braucht, um
  12. einen Scanner für seine Programmiersprache auf die Beine zu stel-
  13. len.  Jetzt wollen wir etwas tiefer in den Compilerbau eindringen
  14. und uns ein Bild davon verschaffen, was alles geschieht, wenn der
  15. Parser  des  Compilers  die  vom  Scanner  erhaltene  Symbolfolge
  16. "durchnudelt".  Die  einzelnen  Stationen  im Parser werden dabei
  17. immer  unter  dem  Gesichtspunkt der "allgemeinen Verwendbarkeit"
  18. beleuchtet  -  die Anwendung der vorgestellten Verfahren ist, wie
  19. schon  früher einmal bemerkt wurde, nicht allein auf die Herstel-
  20. lung  von  (Pascal-)Compilern beschränkt, sondern findet auch bei
  21. anderen Programmierobjekten wie Datenbankprogrammen oder Adventu-
  22. ren  (Satzerkennung)  Verwendung.  Nun  genug der Vorrede, einmal
  23. tief durchgeatmet und los geht's :
  24.  
  25.  
  26. Die Rolle des Parsers im Übersetzer
  27.  
  28. Die  Aufgabe  eines  Compilers  besteht darin, wohlgeformte Sätze
  29. einer  Programmiersprache  zu erkennen und daraus semantisch äqu-
  30. ivalenten  Code  zu  erzeugen.  Trifft der Übersetzer dagegen auf
  31. einen  Satz, der nicht "wohlgeformt" ist, so muß er entsprechende
  32. Aktionen  (Errorhandling) auslösen. Diesen Prozess der Satzerken-
  33. nung  nennt  der  Informatiker  Zerteilung (Parsing). Die Art und
  34. Weise, in der geparst wird, spielt für die Komplexität des Compi-
  35. lers eine entscheidende Rolle. Es ist sicherlich nicht schwierig,
  36. einen  Parser  so  zu konstruieren, daß er bei einem auftretenden
  37. Syntaxfehler  eine  entsprechende  Fehlermeldung ausgibt und dann
  38. den  Zerteilungsprozeß  abbricht.  Der Parsing-Algorithmus sollte
  39. jedoch  in  der  Lage sein, Fehler in Programmen so zu handhaben,
  40. daß  der  Übersetzer  den restlichen Programmtext in vernünftigem
  41. Rahmen  weiter  bearbeiten kann. Ein großes Problem bei der Über-
  42. setzung ist dabei in den meisten Fällen sicherlich nicht die syn-
  43. taktische  Struktur, sondern die semantische Definition der Spra-
  44. che.  So  hängt es vorwiegend gerade von der Semantik ab, ob eine
  45. Sprache  in  einem Pass übersetzt werden kann, oder ob mindestens
  46. zwei  Pässe  benötigt  werden. Ähnlich wie bei der Behandlung des
  47. Scanners,  so soll auch hier ein Bildchen den Informationsfluß im
  48. Parser in entsprechender Weise verdeutlichen.
  49.  
  50. Abbildung 1 : Parser-Interface
  51.  
  52.  
  53.      ──────────────           ───────           ───────────────
  54.     ( lexikalische )────────>( Parser)────────>( systematische )
  55.     (   Analyse    )          ─┬───┬─          (    Analyse    )
  56.      ──────────────            │   │            ───────────────
  57.                                │   │
  58.                                │   │
  59.                                │   │
  60.                             ───┴───┴───
  61.                            (           )
  62.                            (   Error   )
  63.                            (           )
  64.                            (  Handler  )
  65.                            (           )
  66.                             ───────────
  67.  
  68.  
  69.  
  70. Kleine Auffrischung und Rückblick auf die erste Folge
  71.  
  72. Wir  wollen  uns  nun ein wenig an die Grundlagen zum Compilerbau
  73. (1.Folge)  erinnern.  Von dem Wissen, was wir uns dort angeeignet
  74. haben,  benötigen wir gerade im Parser eine ganze Menge. Mal ehr-
  75. lich  :  sind  Begriffe  wie BNF, Grammatik, Syntax etc. noch gut
  76. geläufig  ?  Zur Erinnerung seien sie hier nochmals ganz kurz er-
  77. wähnt (genaueres steht in der Ausgabe 9/87 von Pascal-Internatio-
  78. nal)  :  In einer Programmiersprache können Folgen von Wörtern zu
  79. Sätzen  konstruiert  werden, die das Bild der Sprache formen. Die
  80. Syntax  einer  Programmiersprache  ist eine Menge von Regeln, die
  81. festlegt,  ob ein Satz wohlgeformt ist oder nicht. Der 1963 erst-
  82. mals erschienene ALGOL60 Report enthält eine Notation zur Syntax-
  83. Beschreibung  der  Programmiersprache ALGOL. Diese Notation wurde
  84. auch  für andere Sprachen übernommen und wird nach ihren Entwick-
  85. lern  Backus-Naur-Form (BNF) genannt. Die genaue Konstruktion und
  86. der Aufbau von BNF's wurde bereits in der vorletzten Folge erläu-
  87. tert  und dürfte wohl noch geläufig sein. Um die gleiche Zeit et-
  88. wa,  in  der  die  BNF ausgedacht wurde, entwickelte der Linguist
  89. Noam  Chomsky  seine  Theorien über Grammatiken. Einen speziellen
  90. Typ  von Grammatiken nannte er kontextfreie Grammatiken . Die De-
  91. finition  von  kontextfreien Grammatiken wurde bereits in der er-
  92. sten  Folge eingeführt und kommt auch hier zur Anwendung. Zur Er-
  93. innerung nochmals die Schreibweise :
  94.  
  95. Eine kontextfreie Grammatik G ist ein Vier-Tupel G=(T,N,P,Z) mit:
  96.        - T als Menge der Terminalen,
  97.        - N als Menge der Nichtterminalen,
  98.        - P als Produktionsmenge,
  99.        - Z als Startsymbol,
  100.        - V als Vereinigungsmenge von T und N.
  101.  
  102. Die  Frage  danach, ob eine eingegebene Zeichenfolge ein Satz der
  103. Sprache ist, die durch die zugehörige Grammatik erzeugt wird, war
  104. und  ist Gegenstand zahlreicher Studien auf dem Gebiet der Synta-
  105. xanalyse,  die eine Menge von brauchbaren und verwendbaren Ansät-
  106. zen  geliefert  haben.  Einem  möglichen Ansatz zur Lösung dieses
  107. Problems, der gleichzeitig auch der einfachste Weg ist, liegt die
  108. Idee  des Kellerautomaten zugrunde. Um es gleich zu Beginn zu sa-
  109. gen  :  zum  tieferen  Verständnis von Kellerautomaten, sowie von
  110. Syntaxanalysen  mit  Hilfe  von  Kellerautomaten gehört noch eine
  111. gehörige  Portion  Theorie. Um jedoch die Praktiker und die Intu-
  112. itions-Programmierer  unter  den  Lesern nicht vom Feld zu jagen,
  113. sollen  alle hier beschriebenen Verfahren an Beispielen erläutert
  114. werden, um den Rahmen des menschlich Verstehbaren nicht zu spren-
  115. gen. Begleitende Ausführungen sind so konzipiert, daß das Prinzip
  116. des  einzelnen  Verfahrens herausgestellt wird. Tiefgreifende Er-
  117. klärungen  und formale Beweise dafür, daß die einzelnen Algorith-
  118. men  auch ihren Anforderungen genügen, finden sich dagegen in der
  119. angegebenen  Literatur. Dort können sich interessierte Hobbyisten
  120. und Profis den totalen Durchblick verschaffen.
  121.  
  122. Kellerautomaten
  123.  
  124. Der  neue  Begriff "Kellerautomat" läßt sich von den altbekannten
  125. Begriffen  des Automaten und des Kellers ableiten. Was ein deter-
  126. ministischer  endlicher  Automat ist, wird dem aufmerksamen Leser
  127. der beiden bisherigen Folgen wohl nicht verborgen geblieben sein,
  128. und  auch  die Bedeutung des Kellers wird einigen nicht fremd er-
  129. scheinen.  Ein  Keller  (engl. stack ) ist eine Datenstruktur mit
  130. folgenden Operationen in Pascal-Notation :
  131.  
  132. - procedure push(var k:keller; x:item);
  133.   Ablegen  (kellern)  des Elements x auf die Kellerspitze (top of
  134.   stack).
  135.  
  136. - procedure pop(var k:keller);
  137.   Das  oberste  Element des Kellers wird von der Kellerspitze ge-
  138.   löscht  (entkellern).  Der  Keller  reduziert sich dabei um ein
  139.   Element.
  140.  
  141. - function top(k:keller):item;
  142.   Liesert das an der Kellerspitze befindliche Element zurück. Der
  143.   Kellerinhalt bleibt dabei unverändert.
  144.  
  145. - function empty(k:keller):boolean;
  146.   empty=true genau dann, wenn der Keller leer ist.
  147.  
  148. - function create:keller;
  149.   definiert einen neuen, leeren Keller. ( empty(create)=true )
  150.  
  151. Ein Keller arbeitet also nach dem altbewährten LIFO Prinzip (Last
  152. In,  Last  Out).Einem  sich  hartnäckig haltenden Gerücht zufolge
  153. sollen  ja auch Beamte nach diesem LIFO-Prinzip arbeiten : Grund-
  154. sätzlich wird zuerst das bearbeitet, was zuletzt auf den Schreib-
  155. tisch  gekommen ist. Wehe dem armen Bürger, dessen Akte zuunterst
  156. im  Stapel  ruht (- und ruht - und ruht ). Gegen das LIFO-Prinzip
  157. hilft  in  diesem Fall nur Geduld. Aber zurück zu unserem Arbeit-
  158. splatz. Wirft man das Keller- und Automatenkonzept einfach zusam-
  159. men,  so  kommt  man dem Arbeitsprinzip des Kellerautomaten schon
  160. ziemlich  nahe. In graphischer Darstellung arbeitet ein Kellerau-
  161. tomat etwa wie folgt :
  162.  
  163. Abbildung 2 : Kellerautomat.
  164.  
  165.   Eingabe:
  166.  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
  167.  │ a │ b │ b │ a │ b │ b │ a │ b │ b │ a │ b │ b │ a │   │ ...
  168.  └───┴───┴───┴───┴───┴───┴───┴┬─┬┴───┴───┴───┴───┴───┴───┘
  169.                               │ │
  170.                               │ │
  171.   ┌─────────────┐             │ │           Keller (stack)
  172.   │  Endliches  ├────────>────┘ │               ┌───┐
  173.   │ Gedächtnis  │               │               │ b │
  174.   └─────────────┘               │               ├───┤
  175.                                 │               │ a │
  176.                                 │               ├───┤
  177.                                 │               │ b │
  178.                                 │               ├───┤
  179.                                 │               │ a │
  180.                                 │               ├───┤
  181.                                 │               │ b │
  182.                                 │               ├───┤
  183.                                 └─────────>─────│ a │
  184.                                                 ├───┤
  185.                                                 │   │
  186.                                                 ├───┤
  187.                                                 │   │
  188.                                                 └───┘
  189.                                                  .
  190.                                                  .
  191.  
  192.  
  193.  
  194. Anschaulich  betrachtet,  ist der Kellerautomat also in der Lage,
  195. ein Zeichen zu lesen und, abhängig vom gelesenen Zeichen der Ein-
  196. gabe,  seinen Keller entsprechend zu verändern. Eine weitere, zu-
  197. sätzliche  Fähigkeit  wollen  wir  unserem Kellerautomaten jedoch
  198. noch  zugestehen  :  er soll in der Lage sein, seinen Zustand und
  199. den  Kellerinhalt  auch spontan ändern zu können, das heißt, ohne
  200. dabei  ein  Zeichen aus der Eingabe zu lesen oder zu verarbeiten.
  201. Deterministische endliche Automaten besitzen nach unserer Defini-
  202. tion  diese  Eigenschaft  noch nicht. Formal sieht die Definition
  203. dann so aus :
  204.  
  205. Ein Kellerautomat A ist ein 7-Tupel A=(T,Q,R,q[0],F,S,s[0])mit:
  206. -  T,Q,q[0],F  wie beim endlichen Automaten. T soll zusätzlich zu
  207.    den  Eingabezeichen  noch  ein  eindeutig bestimmtes Zeichen #
  208.    besitzen, mit dem die Eingabefolge abgeschlossen wird.
  209. - S ist das Kelleralphabet. Es kann Elemente aus T oder Q enthal-
  210.   ten, aber auch andere Zeichen sind zugelassen.
  211. -  s[0] aus S ist die Kellervorbesetzung. Vor der Abarbeitung der
  212.   Eingabe  kann  der Keller also mit anderen Zeichen aus dem Kel-
  213.   lerralphabet  besetzt  werden. s[0] kann auch das leere Zeichen
  214.   >e< sein.
  215. -  R  entspricht den Regeln des deterministisch endlichen Automa-
  216.   ten, die nur  um  einen Kellerteil erweitert sind. In der dabei
  217.   verwendeten Formulierung werden  die  Zeichen ++ für Mengenver-
  218.   einigung und -- für Mengendifferenz verwendet.
  219.  
  220.  
  221. Die Regeln haben die Form:
  222. sqaw  ->  s'q'w  mit :
  223. s,s'  aus  S*,
  224. q,q'  aus Q,
  225. a aus T+ +{e}- -{#} und w aus T*.
  226.  
  227. Die Sprache L(A) , die von einem Kellerautomaten akzeptiert wird,
  228. definieren wir wie folgt :
  229.  
  230. L(A):={w aus (T--{#})*
  231.       | s0,p0# ->* q# , q aus F}
  232.    
  233. Verbal formuliert bedeutet das : Beim Start ist der Kellerautomat
  234. im  Zustand  q[0],  hat die Kellervorbesetzung so und die Eingabe
  235. w,die durch ein # begrenzt wird. Gelangt der Kellerautomat in den
  236. Zustand  q aus F (F = Endzustandsmenge), wobei sowohl die Eingabe
  237. als auch der Keller leer sind, dann ist die Eingabe w Element der
  238. Sprache L(A). Der Übersicht halber (und zum besseren Verständnis)
  239. seien  die  unterschiedlichen Regeltypen eines Kellerautomaten in
  240. Tabellenform dargestellt:
  241.  
  242. Übergänge            │     Regeltyp
  243. ─────────────────────┼─────────────────────
  244. zeichenbestimmend    │   sqaw         -> s'q'w
  245. spontan              │   sqw          -> s'q'w
  246. kellernd(push)       │   s[1]qaw      -> s[1]s[2]q'w
  247. entkellernd(pop)     │   s[1]s[2]qaw  -> s[1]q'w
  248. ersetzend            │   s[1]qaw      -> s[2]q'w
  249.  
  250.  
  251. Beispiel eines Kellerautomaten :
  252.  
  253. Gesucht sei ein  Kellerautomat,  der die Sprache L={wcw[r]|w aus
  254. {a,b}*} akzeptiert. (w[r] bedeutet w[Reverse(Rückwärts])).
  255. Der Automat habe die Form A=(T,Q,R,q0,F,S,s0) mit:
  256.  
  257. T={a,b,c} ; Q={q[0],q[1]} ; S={a,b} ; s[0]=e ;
  258. F={q[1]}  ; r aus S*      ; w aus T*
  259.  
  260.  
  261.    R : rq[0]aw  -> raq[0]w  (1)
  262.        rq[0]bw  -> rbq[0]w  (2)
  263.        rq[0]cw  -> rq[1]w   (3)
  264.        raq[1]aw -> rq[1]w   (4)
  265.        rbq[1]bw -> rq[1]w   (5)
  266.  
  267. Um die Arbeitsweise von A zu illustrieren, soll der Kellerautomat
  268. auf  die  Folge abbcbba   angewendet  werden :
  269.  
  270.     Zustand    │ Eingabe       │  Keller        │  Übergang     │
  271. ───────────────┼───────────────┼────────────────┼───────────────┼─
  272. q[0]           │ abbcbba       │         e      │     -         │
  273. q[0]           │  bbcbba       │         a      │     1         │
  274. q[0]           │   bcbba       │        ba      │     2         │
  275. q[0]           │    cbba       │       bba      │     2         │
  276. q[1]           │     bba       │       bba      │     3         │
  277. q[1]           │      ba       │        ba      │     5         │
  278. q[1]           │       a       │         a      │     5         │
  279. q[1]           │       e       │         e      │     4         │
  280.  
  281.  
  282.  
  283. Das  Wort abbcbba gehört also zur oben definierten Sprache L. So-
  284. weit  nun zu Kellerautomaten. Was, fragt sich der aufmerksame Le-
  285. ser,  haben  nun Kellerautomaten mit kontextfreien Grammatiken zu
  286. tun?  Ganz  einfach: es existiert ein Satz, der besagt, daß es zu
  287. jeder  kontextfreien  Grammatik  einen Kellerautomaten A gibt mit
  288. L(A)=L(G).  So weit, so gut. Danach ist es relativ einfach, einen
  289. passenden Parser für die zugehörige Grammatik zu finden. In unse-
  290. rem Fall bedeutet das :
  291. Man nimmt die Pascal-Grammatik her, konstruiert daraus einen Kel-
  292. lerautomaten  und schaut dann nach, ob der Kellerautomat das ein-
  293. gegebene Programm akzeptiert oder nicht, das heißt, ob die Syntax
  294. korrekt  oder  fehlerhaft ist. Einen kleinen Haken gibt es aller-
  295. dings  bei  der ganzen Sache. Effizientes Parsing setzt einen de-
  296. terministischen Kellerautomaten voraus, und deterministische Kel-
  297. lerautomaten  existieren  nur  für Unterklassen von kontextfreien
  298. Grammatiken.  Wir  werden  später noch erkennen müssen, daß Stan-
  299. dard-Pascal  zu  allem Übel - wie könnte es auch anders sein - in
  300. einigen  Fällen  nicht  uneingeschränkt  den Anforderungen dieser
  301. speziellen  Unterklassen genügt. Nun, wir werden uns trotzdem ei-
  302. nen  deterministischen  Kellerautomaten für unsere Grammatik hin-
  303. biegen.  Doch dazu müssen wir und erst einmal etwas näher mit den
  304. unterschiedlichen Zerteilungsverfahren beschäftigen.
  305.  
  306.  
  307. Zerteilungsverfahren
  308.  
  309. Grundsätzlich  gibt  es  zwei Arten von Zerteilungsverfahren. Zum
  310. einen  ist  da die zielbezogene Zerteilung ( LL(k)-Zerteilung mit
  311. k>0   )   und   zum   anderen   die  quellbezogene  Zerteilung  (
  312. LR(k)-Zerteilung mit k>0 ) zu nennen.
  313.  
  314. Die  quellbezogene  Zerteilung ( Bottom-up-Analyse ) verfolgt den
  315. Ableitungsbaum von der Blättern zur Wurzel ( Quelle ). Das dabei
  316. verwendete  Konzept  ist zwar mächtiger als die zielbezogene Zer-
  317. teilung,  jedoch benötigt es zur Konstruktion auch ein wesentlich
  318. größeres  theoretisches  Basiswissen.  Daher  soll die Bottom-up-
  319. Analyse  an dieser Stelle auch nur namentlich erwähnt bleiben, da
  320. deren  vollständige  Behandlung  den  Rahmen dieser Reihe gehörig
  321. sprengen   würde.   Wer  sich  einen  tieferen  Einblick  in  die
  322. LR(k)-Zerteilung  verschaffen  will,  dem  sei  hier das Buch von
  323. M.A.  Harrison,  Introduction to formal language theory, Addison
  324. Wesley 1978,  empfohlen.
  325.  
  326. Im  Gegensatz  dazu  wird bei der zielbezogenen Zerteilung ( Top-
  327. down- Analyse) versucht, den Ableitungsbaum von der Wurzel zu den
  328. Blättern (Ziel) aufzubauen. Diesem LL(1)-Verfahren werden wir uns
  329. im Folgenden eingehender zuwenden. Bevor die LL(1)-Analyse jedoch
  330. vollständig vorgestellt werden kann, müssen noch einige notwendi-
  331. ge  Vorbetrachtungen  zu den Anfängen von Wörtern w aus V gemacht
  332. werden.
  333.  
  334. Der k-Anfang von w aus V*, - man schreibt das auch als k:w -, ist
  335. definiert als
  336.  
  337.        k:w := { w#     , falls |w|<k
  338.                 x      , falls w=xy und |x|=k }
  339.  
  340.        (|w| ist die Länge des Wortes w)
  341.  
  342. Der  k-Anfang ist also nichts anderes als der ganz normale Anfang
  343. eines Wortes, wobei die natürliche Zahl k die Länge dieses Anfan-
  344. ges angibt.
  345.  
  346. Ein Beispiel soll das erläutern :
  347.  
  348. Sei T={a, b, c} und w=abccb, dann sind z.B.:
  349.  
  350.       1:w = a
  351.       3:w = abc
  352.       5:w = abccb
  353.       6:w = abccb#
  354.       n:w = abccb#  für alle n>=6
  355.  
  356. Weiterhin faßt man die Menge aller terminalen k-Anfänge von w aus
  357. V*  zur  Menge Anf[k](w) zusammen. Formal definiert sieht das wie
  358. folgt aus :
  359.  
  360. Anf[k](w) := {x | es ex. ein v aus T* mit w=> *v und x=k:v }
  361.  
  362. An  dieser  Stelle trifft man in der englischsprachigen Literatur
  363. meist  auf  den  Begriff first[k](w) anstelle von Anf[k](w). Auch
  364. hier soll ein kleines Beispiel die Definition erläutern :
  365.  
  366. Sei G=(T,N,P,Z) mit
  367.  
  368.     T={a, b, c} ; N={S, A, B ,C} ; Z=S und
  369.  
  370.      P: S -> A | B | C
  371.         A -> bBa
  372.         B -> aAa
  373.         C -> cCc ,
  374.  
  375.    dann ist
  376.        
  377.      Anf1 (S) = {a, b, c}
  378.      Anf1(A) = {b}
  379.      Anf1(B) = {a}
  380.      ....
  381.             
  382. Wie  man  sieht,  lassen sich für kleinere Grammatiken die Mengen
  383. Anf[k](w) leicht zu Fuß berechnen. Erreichen Grammatiken dahinge-
  384. gen  den Umfang von Programmiersprachen-Grammatiken, so wird eine
  385. der- artige Bestimmung der einzelnen Anfänge schon wegen des gro-
  386. ßen  Arbeitsaufwandes  im  Keim erstickt werden. Glücklicherweise
  387. exi-  stiert  ein einfacher Algorithmus, mit dessen Hilfe die Be-
  388. stimmung  der  Anfänge auch automatisch durchgeführt werden kann.
  389. Da  wir  uns  nur mit dem LL(1)-Verfahren beschäftigen, benötigen
  390. wir nur ein Verfahren, das alle 1-Anfänge berechnet. Diesen Algo-
  391. rithmus wollen wir uns hier zu Gemüte führen.
  392.  
  393. Berechnung von Anf1(x) (gleich Anf(x))
  394.  
  395. Nach  Definition  ist  # aus Anf(x) genau dann, wenn x=>*e (e ist
  396. das  leere  Wort). Zu Beginn wird die Menge der Anfänge wie folgt
  397. initialisiert :
  398.  
  399.      Anf(t) := {t} für alle t aus T
  400.      Anf(X) := { } für alle X aus N.
  401.      repeat
  402.        for each X -> x1 x2...xn aus P do begin
  403.          i:=1;
  404.          weiter:=true;
  405.          W:={ };
  406.          while (i<=n) and weiter do begin
  407.             W:=W  ++  (Anf(x1)--{#});
  408.             if # aus Anf(x1) then i:=i+1
  409.                              else weiter:=false
  410.          end;
  411.          if weiter then W:=W ++ {#};
  412.          Anf(X):=Anf(X) ++ w
  413.        end
  414.      until alle Anf(X) unverändert
  415.  
  416. Ein Beispiel soll diesen Algorithmus erläutern :
  417.    
  418. Gegeben ist die folgende Grammatik G=(T,N,P,Z) mit :
  419.    
  420.      N={E,E1,T,T,P}
  421.      T={a,b,c,(,),*}
  422.      Z=E ist das Startsymbol
  423.    
  424. Die zugehörigen Produktionen lauten :
  425.  
  426.      (1)  E  -> T E1
  427.      (2)  E1 -> +E | e
  428.      (3)  T  -> F T1
  429.      (4)  T1 -> T | e
  430.      (5)  F  -> P F1
  431.      (6)  F1 -> * F1 | e
  432.      (7)  P  -> (E) | a | b | c
  433.  
  434. Wendet man nun jeweils auf die einzelnen Produktionen Schritt für
  435. Schritt den obigen Algorithmus an, so ergibt sich folgende Tabel-
  436. lenaufstellung für die einzelnen Nichterminale :
  437.  
  438.  
  439.                     │ Anf(x)    │ Anf(x)    │
  440.                 ────┼───────────┼───────────┼──
  441.                  E  │ Anf(T E1) │ (,a,b,c   │
  442.                  E1 │ +,#       │ +,#       │
  443.                  T  │ Anf(F T1) │ (,a,b,c   │
  444.                  T1 │ Anf(T),#  │ (,a,b,c,# │
  445.                  F  │ Anf(P F1) │ (,a,b,c   │
  446.                  F1 │ *,#       │ *,#       │
  447.                  P  │ (,a,b,c   │ (,a,b,c   │
  448.  
  449.  
  450. Zum  besseren Verständnis der Tabelleneinträge betrachten wir nun
  451. die Produktion E -> T E1 etwas näher :
  452.  
  453.     E
  454.     |                    Anwendung von Regel (3), es wird der
  455.     |                    Anfang von T bestimmt.
  456. Anf(T E1)
  457.     |                    Regel (3). Da Anf(T)=Anf(F) ist, wird im
  458.     |                    nächsten Schritt Anf(F) ermittelt.
  459.     Anf(F T1)
  460.         |                Regel (3)
  461.         |
  462.         Anf(P F1)
  463.             |            Regel (2). Erst hier wird eine Menge von
  464.             |            von Terminalen ermittelt. Da diese Menge
  465.             { (,a,b,c) } nicht  das  leere Wort enthält, ist es
  466.                          nicht erforderlich, Anf(F1) zu bilden.
  467.                          Der Algorithmus endet an dieser Stelle.
  468.  
  469.  
  470. Somit ergibt sich für das Nichtterminal E :
  471.  
  472.      Anf[1](E) = { (,a,b,c }
  473.  
  474. Ähnlich  wie die terminalen k-Anfänge eines Wortes w aus V*, kann
  475. man  auch die Menge der terminalen Zeichenreihen der Länge k, die
  476. auf  w  folgen können und mit Folge[k](w) (engl.follow[k](w)) be-
  477. zeichnet werden, definieren als :
  478.  
  479. Folge[k](w) := { x | es ex. ein v aus T* und
  480.                  Z=> *uwv, wobei x=k:v }
  481.  
  482. Auch die Folge[k](w)-Menge kann mit dem nachfolgenden Algorithmus
  483. automatisch generiert werden.
  484.  
  485.  
  486. Berechnung von Folge[1](x) (=Folge(x))
  487.  
  488. Zuerst werden die Mengen Folge(Z) und Folge(X) mit
  489.  
  490.      Folge(Z) = {#} und
  491.      Folge(X) = { } für alle X aus N--{Z},
  492.  
  493. vorbesetzt. Der zur weiteren Berechnung der Folge-Mengen benötig-
  494. te Algorithmus lautet :
  495.  
  496.  
  497.      repeat
  498.        for each X -> uYv aus P do begin
  499.          Folge(Y) := Folge(Y) ++ (Anf(v) -- {#});
  500.          if (v=e) or (# aus Anf(v))
  501.            then Folge(Y):=Folge(Y) ++ Folge(X)
  502.        end
  503.      until alle Folge(Y) unverändert;
  504.  
  505. Zur  Erklärung  der Arbeitsweise dieses Verfahrens sei wieder die
  506. Grammatik G aus obigem Beispiel gewählt :
  507.  
  508.             │ Folge(x)                   │ Folge(x)
  509.         ────┼────────────────────────────┼───────────
  510.          E  │ #,),Folge(E1)              │ #,)
  511.          E1 │ Folge(E)                   │ #,)
  512.          T  │ Anf(E1),Folge(E),Folge(T1) │ +,#,)
  513.          T1 │ Folge(T)                   │ +,#,)
  514.          F  │ Anf(T1),Folge(T1)=Folge(T) │ (,a,b,c,+,#,)
  515.          F1 │ Folge(F)                   │ (,a,b,c,+,#,)
  516.          P  │ Anf(F1),Folge(F)           │ *,(,a,b,c,+,#,)
  517.  
  518.  
  519. Betrachten  wir  zur  Tabellenerläuterung die Berechnung von Fol-
  520. ge(T).  Zunächst  werden  alle Regeln gesucht, in denen T auf der
  521. rechten Seite der Ableitungsregeln auftritt. Das trifft in diesem
  522. Fall  auf  die Produktionen (1) und (4) zu. Aus dem Verfahren er-
  523. gibt  sich,  daß im nächsten Schritt der Anfang des Teilwortes zu
  524. bestimmen  ist,  das  auf T folgt. Für Regel (1) erhält man dabei
  525. die  Menge  M{1}={+,#} und für Regel (4) die Menge M{2}={ }. Eine
  526. Vereinigung der Menge M{1}--{#} mit M{2} liefert als Folge(T) die
  527. Menge  {+}.  Da  # aus Anf(E1) ist, muß wegen Regel (1) noch Fol-
  528. ge(E)  bestimmt werden. Auch in Regel (4) tritt kein N aus V nach
  529. T auf, weshalb hier noch Folge(T1) bestimmt werden muß.
  530.  
  531. Daraus ergibt sich als Zwischenergebnis :
  532.      
  533.       Folge(T)={+,Folge(E),Folge(T1)}
  534.  
  535. Nachdem der Algorithmus auf Folge(E) und Folge(T1) angewandt wur-
  536. de, erhält man :
  537.  
  538.       Folge(E) ={#,)}
  539.       Folge(T1)={+,#,)}
  540.  
  541. Damit ergibt sich für Folge(T) als Endergebnis :
  542.  
  543.       Folge(T) = {+,#,)}
  544.    
  545. Soweit zu Anf[k](w) und Folge[k](w). Um das Ziel unserer Bemühun-
  546. gen  nicht  aus  den Augen zu verlieren, sei es nochmals erwähnt:
  547. Wir sind auf der Suche nach einem deterministischen Kellerautoma-
  548. ten  A  mit L(A)=L(G). G ist unsere Standard-Pascal-Grammatik. Es
  549. gibt nun einen Satz, der besagt, daß genau dann ein deterministi-
  550. scher  Kellerautomat  existiert,  wenn  die  zugehörige Grammatik
  551. LL(k)  (in  unserem Fall LL(1)) ist. Nun, was besagt dieses LL(1)
  552. eigentlich  ?  LL(1) bedeutet nichts anderes, als daß die Eingabe
  553. von  links nach rechts gelesen wird, und dabei der zugehörige Ab-
  554. leitungsbaum  ebenfalls  von  links  nach rechts (Linksableitung)
  555. aufgebaut  wird. In jedem Schritt darf hierbei nicht mehr als ein
  556. Zeichen  aus  der Eingabe zur Entscheidung beitragen (ein Zeichen
  557. Vorschau).
  558. Formal wird das so ausgedrückt :
  559.  
  560. Eine  kontextfreie Grammatik G=(T,N,P,Z) heißt LL(k)-Grammatik zu
  561. gegebenen k>0, wenn für je zwei Linksableitungen
  562.  
  563.       Z -> uAv -> uxv  -> *uy
  564.       Z -> uAv -> ux'v -> *uy'
  565.  
  566. mit A aus N, v,x,x' aus V* und u,y,y' aus T* folgt :
  567. aus k:y=k:y' folgt : x=x', d.h. A -> x = A -> x'.
  568.    
  569. Äquivalent gilt dann für jedes Produktionenpaar A -> x, A -> x'
  570. mit x<>x' :
  571.    
  572. Anf[k] (x Folge [k](A))--Anf[k] (x' Folge[k] (A))={ }.
  573.  
  574. Falls  k=1  ist  und  keine  Ableitung der Form S -> e (e= leeres
  575. Wort, S aus N) existiert, gilt weitere viel einfachere Aussage:
  576.  
  577. Anf[1](x) und Anf[1](x') müssen disjunkt sein.
  578.  
  579. Mit  den so erarbeiteten Grundlagen ist es nun möglich, einen de-
  580. terministischen  Kellerautomaten für eine LL(k)-Grammatik anzuge-
  581. ben. Die Zustände des Kellerautomaten entsprechen dabei Situatio-
  582. nen  (items  ) in der Bearbeitung von speziellen Produktionen der
  583. Grammatik. Eine Situation hat die folgende Gestalt :
  584.  
  585. [X -> Y.Z] aus Q   (Q ist Zustandsmenge des Kellerautomaten)
  586.  
  587. Der Punkt in der Situation gibt die Analyseposition in der jewei-
  588. ligen  Produktion an. ((X -> YZ) aus Produktionsmenge P der Gram-
  589. matik). Aufgabe ist es jetzt, die Zustandsmenge des Kellerautoma-
  590. ten  aus  den  Produktionen der Grammatik zu gewinnen. Dazu defi-
  591. niert  man  als  Startzustand  q[0]:=[Z -> .S]. Der Keller ist zu
  592. Beginn  leer  (Kellervorbesetzung s[0] =e), Q:={q[0]}, R:={ } und
  593. F:={[Z  ->  S.]}. Für jeden Zustand q=[A ->X.Y] erweitern wir die
  594. Mengen des Kellerautomaten wie folgt:
  595.  
  596. 1.) q=[A -> x.] :
  597. Erweitere R um : R:=R++{qe -> e} (entkellern)
  598.  
  599.  2.) q=[A -> x.ay'] :
  600. Bilde neuen Zustand q'=[A -> xa.y'] und q' ist neuer Nachfolgezu-
  601. stand.Erweitere  Q um : Q:=Q++{q'} und R um : R:=R++{qa -> q'} (a
  602. aus T).
  603.  
  604. 3.) q=[A -> x.By'] :
  605. Bilde  neuen  Zustand q'=[A -> x'B.y'] und kellere ihn. Bilde für
  606. jede  Produktion  B  ->  Z[1],..,B -> Z[n] neue Zustände h[1]
  607. =[B->.Z[1]],  .. ,h[n]=[B->.Z[n]].
  608.  
  609. Die  Zustandsmenge des Kellerautomaten wird entsprechend um diese
  610. neuen  Zustände erweitert : Q := Q ++ {h[1],..,h [n]} ++ {q'} und
  611. die Regelmenge R vergrößert sich um die Regeln :
  612.  
  613.  R:=R  ++ {qw[1]->q'h[1]w[1] | w[1] aus W[1]} .. ++ .. ++ {qw [n]
  614. ->q'h[n]w[n]  |  w[n] aus W[n]} mit W[i]:=Anf(Z[i])für alle i aus
  615. {1,..,n}
  616.  
  617. Abhängig  vom nächsten Eingabezeichen x aus T, das in genau einer
  618. der  Mengen  W[i] liegen muß, wird h[i] neuer Nachfolgezustand im
  619. Automaten.
  620.  
  621. Zur  Veranschaulichung  konstruieren  wir einen deterministischen
  622. Kellerautomaten  für eine LL(1)-Grammatik. Sei die Ausdrucksgram-
  623. matik
  624.  
  625.    G=(T,N,P,Z)  gegeben   mit   T={i,+,(},
  626.    N={Z,A,A',F} und P :
  627.  
  628.    Z  -> A
  629.    A  -> FA'
  630.    A' -> +FA'
  631.    A' -> e
  632.    F  -> i
  633.    F  -> (A)
  634.  
  635. Für  die  Berechnung der W[i] aus 3) benötigen wir die 1-Anfänge,
  636. die  mit dem vorgestellten Algorithmus nun leicht bestimmt werden
  637. können. Es ist
  638.  
  639.           │ Anf(x) │ Folge(x)
  640.      ─────┼────────┼──────────
  641.        Z  │ i,(    │ #
  642.        A  │ i,(    │ #,)
  643.        A' │ +,#    │ #,)
  644.        F  │ i,(    │ +,#,)
  645.  
  646.  
  647. Zum  korrekten Nachweis der LL(1)-Eigenschaft überprüfen wir noch
  648. schnell,  daß  Anf(+FA' Folge(A'))={+} und Anf(e Folge(A'))={#,)}
  649. disjunkt  sind={  }.
  650.  
  651.  
  652. Ein  kleines Beispiel soll die Funktionstüchtigkeit des so erhal-
  653. tenen deterministischen Kellerautomaten zeigen :
  654.  
  655.  
  656.   Keller                   │ Zustand  │ Eingabe  │ Linksableitung
  657. ───────────────────────────┼──────────┼──────────┼───────────────
  658. /                          │ q[0]     │ (i+i)#   │ A
  659. q[1]                       │ q[2]     │ (i+i)#   │ FA'
  660. q[1],q[3]                  │ q[5]     │ (i+i)#   │ (A)
  661. q[1],q[3]                  │ q[6]     │ i+i)#    │
  662. q[1],q[3],q[7]             │ q[2]     │ i+i)#    │ FA'
  663. q[1],q[3],q[7],q[3]        │ q[9]     │ i+i)#    │ i
  664. q[1],q[3],q[7],q[3]        │ q[10]    │ +i)#     │
  665. q[1],q[3],q[7]             │ q[3]     │ +i)#     │
  666. q[1],q[3],q[7],q[4]        │ q[12]    │ +i)#     │ +FA'
  667. q[1],q[3],q[7],q[4]        │ q[13]    │ i)#      │
  668. q[1],q[3],q[7],q[4],q[14]  │ q[9]     │ i)#      │ i
  669. q[1],q[3],q[7],q[4],q[14]  │ q[10]    │ )#       │
  670. q[1],q[3],q[7],q[4]        │ q[14]    │ )#       │
  671. q[1],q[3],q[7],q[4],q[15]  │ q[11]    │ )#       │ e
  672. q[1],q[3],q[7],q[4]        │ q[15]    │ )#       │
  673. q[1],q[3],q[7]             │ q[4]     │ )#       │
  674. q[1],q[3]                  │ q[7]     │ )#       │
  675. q[1],q[3]                  │ q[8]     │ #        │
  676. q[1]                       │ q[3]     │ #        │
  677. q[1],q[4]                  │ q[11]    │ #        │ e
  678. q[1]                       │ q[4]     │ #        │
  679. /                          │ q[1]     │ #        │
  680.  
  681.  
  682.  
  683. Auch wenn es auf den ersten Blick nicht ersichtlich scheinen mag:
  684. das  beschriebene  Verfahren  stellt  eine ausgesprochen einfache
  685. Möglichkeit  zur  Erzeugung  von Zerteilern dar. Die vorgestellte
  686. Methode  wurde  gegen  Ende der 60'er Jahre von Lewis und Stearns
  687. entwofen und eingeführt. Viele Compilerbauer wählen aufgrund grö-
  688. ßerer  Mächtigkeit  heute  andere  Zerteilungsverfahren  als  die
  689. LL(1)-Zerteilung  (LR(k),  LALR(k),  SLR(k)  - Zerteilungen ). Um
  690. sich einen grundlegenden Einblick in den Compilerbau zu verschaf-
  691. fen,  reicht das Verständnis der LL(1)-Analyse jedoch vollständig
  692. aus.  Im  übrigen hat das vorgestellte Verfahren den Vorteil, daß
  693. sich dazu Generatoren bauen lassen, die in der Lage sind, syntak-
  694. tische  Informationen  einer  fast  beliebigen Programmiersprache
  695. aufzunehmen  und  daraus die Implementierung des zugehörigen Par-
  696. sers automatisch zu erzeugen. Die Implementierung unseres Parsers
  697. ist jedoch nach guter alter Manier noch "von Hand gemacht".
  698.  
  699.  
  700. Implementierung von LL(1)-Zerteilern
  701.  
  702. Auch  wenn  einigen  Lesern bei der LL(1)-Theorie die Nackenhaare
  703. hochgegangen  sein mögen, so zeigt sich spätestens bei der Imple-
  704. mentierung dieses Zerteilungsverfahrens einer seiner wesentlichen
  705. Vorteile  : die verhältnismäßig einfache Programmierung. Die Spe-
  706. zifikation ist klar. Als Eingabe dient dem Parser die vom Scanner
  707. erhaltene  Symbolfolge. Ausgegeben werden soll eine Folge von an-
  708. gewandten Produktionen, aus denen sich der zugehörige Ableitungs-
  709. baum  konstruieren  läßt.  In der Ausprogrammierung tauchen dabei
  710. immer wieder 3 "Basisprozeduren" auf, die hier in Pascal-Notation
  711. erläutert werden sollen.
  712.  
  713.  
  714.    var symbol: ... ;
  715.    
  716.    procedure lesen;
  717.    begin
  718.          gib_symbol_aus(symbol);
  719.          symbol:=next_symbol
  720.    end;
  721.  
  722.    procedure akzeptiere(t:symbolklasse);
  723.    begin
  724.        if symbol.klasse=t then lesen
  725.                             else fehlerbehandlung
  726.    end;
  727.  
  728.    procedure gib_produktion_aus(p:produktion);
  729.    begin ... end;
  730.  
  731. Der  zentrale  Algorithmus - der eigentliche Kellerautomat - kann
  732. als tabellengesteuert mit den Regeln R als Übergangsmatrix QxT ->
  733. Q  programmiert  werden. Diese Darstellungsweise kommt dem altbe-
  734. kannten deterministisch endlichen Automaten sehr nahe und besitzt
  735. den Vorteil der schnellen Ausführbarkeit.
  736. Eine  andere  Variante  bietet  hinsichtlich Geschwindigkeit zwar
  737. einige  Nachteile,  spiegelt aber wesentlich stärker die Struktur
  738. der  zu  implementierenden Programmiersprache wider. Die Rede ist
  739. vom  Rekursiven Abstieg (recursiv descent) . Bei diesem Verfahren
  740. wird  jedem  A  aus N eine rekursive Prozedur zugeordnet. Die Zu-
  741. stände  des  deterministischen  Kellerautomaten  entsprechen dann
  742. Programmstellen  in  der Implementierung. Der Stack braucht nicht
  743. explizit programmiert zu werden, sondern baut sich durch die Auf-
  744. rufe  der  einzelnen  Prozeduren von selbst auf (Laufzeitkeller).
  745. Die  Implementierung unserer Ausdrucksgrammatik soll dieses Prin-
  746. zip verdeutlichen :
  747.  
  748.    program Z;
  749.  
  750.    procedure A;
  751.    begin
  752.    gib_produktion_aus( {A -> FA'} );
  753.          F; A'
  754.    end;
  755.  
  756.  
  757.    procedure F;
  758.    begin
  759.      if symbol.klasse in ['i','('] then
  760.      case symbol.klasse of
  761.        'i' : begin
  762.                gib_produktion_aus( {F -> i} );
  763.                    lesen;
  764.              end;
  765.        '(' : begin
  766.                gib_produktion_aus( {F -> (A) };
  767.                    lesen;
  768.                    A;
  769.                    akzeptiere(')')
  770.              end;
  771.      end
  772.      else fehlerbehandlung
  773.    end;
  774.  
  775.    procedure A';
  776.    begin
  777.      if symbol.klasse in ['#','+'] then
  778.      case symbol.klasse of
  779.        '#' : gib_produktion_aus( {A' -> e} );
  780.        '+' : begin gib_produktion_aus( {A' -> +FA'} );
  781.                    lesen; F; A'
  782.              end
  783.      end else fehlerbehandlung
  784.    end;
  785.  
  786.    begin
  787.       gib_produktion_aus( {Z -> A} );
  788.       A;
  789.       akzeptiere('#')
  790.    end.
  791.  
  792.  
  793. So.  Nachdem wir uns nun mit viel Erfolg durch Theorie und Praxis
  794. des  Parsers gekämpft haben, werden wir das in der nächsten Folge
  795. fortsetzen  und uns dann mit der "semantische Analyse" beschäfti-
  796. gen.
  797. Dieses wird dann das letzte Kapitel zum Analyse-Teil sein.
  798. Danach  werden auch die Fans von Programmauszügen auf ihre Kosten
  799. kommen,  da der Quelltext des Compilers als Leitfaden den Synthe-
  800. se-Teil durchziehen wird.
  801.