  1 unit uParser;
  2 
  3 {**********************************************************************}
  4 {*                                                                    *}
  5 {*    M I N I C O M P - 1                                             *}
  6 {*                                                                    *}
  7 {*    Version 1 des Minicompiler-Projekts                             *}
  8 {*                                                                    *}
  9 {*    MODUL 2: Syntaktische Analyse                                   *}
 10 {*                                                                    *}
 11 {*    Das Programm stellt einen einfachen Zeilenparser zur Verf.      *}
 12 {*    der einen einfachen Stackmaschinencode erzeugt.                 *}
 13 {*                                                                    *}
 14 {*                                                                    *}
 15 {*    Abhaengigkeiten:                                                *}
 16 {*    ---------------                                                 *}
 17 {*    Das Programm benoetigt uLexer.pas                               *}
 18 {*                                                                    *}
 19 {*    (C) U. Helmich 10.2.91                                          *}
 20 {*                                                                    *}
 21 {*    grundlegende ueberarbeitet am 12.8.92                           *}
 22 {*    zuletzt bearbeitet am 11.3.94                                   *}
 23 {*    zuletzt bearbeitet am 10.3.95                                   *}
 24 {*    zuletzt bearbeitet am 15.2.96                                   *}
 25 {*    nicht weiter veraendert am 11.05.97                             *}
 26 {*    nicht weiter veraendert am 21.02.98                             *}
 27 {*    Delphi-Version erstellt am 24.05.03                             *}
 28 {*                                                                    *}
 29 {**********************************************************************}
 30 
 31 interface
 32 uses uLexer,stdctrls;
 33 
 34 type  TParser = class
 35                   constructor Init(l,fn : string; m : TMemo);
 36 
 37                   procedure Match(t : tTokentype);
 38                   procedure Term;
 39                   procedure Factor;
 40                   procedure Expr;
 41 
 42                   procedure Parse;
 43 
 44                 private
 45                   look     : tToken;
 46                   line     : string;
 47                   Lexer    : TLexer;
 48                   errstate : integer;
 49                   codefile : text;
 50                   memo     : TMemo;
 51 
 52                   procedure WriteCode(s : string);
 53                   procedure WriteError(s : string);
 54                 end;
 55 
 56 
 57 implementation
 58 uses Sysutils;
 59 
 60 constructor TParser.Init(l,fn : string; m : TMemo);
 61 {  Initialisierung eines Lexer-Objektes und
 62    Anlegen einer leeren Code-Datei
 63 }
 64    begin
 65       line     := l;
 66       Lexer    := TLexer.Init(l,m);
 67       errstate := 0;
 68       assign(codefile,fn);
 69       rewrite(codefile);
 70       close(codefile);
 71       memo := m;
 72    end;
 73 
 74 procedure TParser.WriteCode(s : string);
 75 {  Hilfsprozedur, die den String s in die Code-Datei schreibt und diese
 76    anschließend wieder schließt.
 77 }
 78    begin
 79       append(codefile);
 80       writeln(codefile,s);
 81       close(codefile);
 82    end;
 83 
 84 procedure TParser.WriteError(s : string);
 85 {  Hilfsprozedur, die den String s in die Memobox schreibt
 86 }
 87    begin
 88       memo.Lines.Add(s);
 89    end;
 90 
 91 procedure TParser.Match(t : tTokentype);
 92 {  Hilfsroutine, die ein neues Token vom Lexer holt.
 93    Außerdem wird Match zur Syntaxprüfung eingesetzt, hier wird nämlich
 94    festgestellt, ob das laut Grammatik erwartete Symbol vorliegt.
 95 }
 96    begin
 97       if look.tokentype = t
 98          then Lexer.GetNext(look)
 99          else begin
100             WriteError('<Match> meldet Fehler:');
101             WriteError('Uebergebenes Token t ist ' + TokenToStr(t));
102             WriteError('Lookahead ist aber ' + TokenToStr(look.tokentype));
103          end;
104    end;
105 
106 procedure TParser.Expr;
107 {  Die erste einer Reihe von rekursiven Prozeduren, die den eigentlichen Kern
108    des rekursiven Parsers ausmachen.
109    Expr steht fŸr das Startsymbol der kontextfreien Grammatik, die dem
110    Parser hier zugrunde liegt.
111 }
112    var op : char;
113 
114    begin
115       Term;
116       repeat
117          if look.tokentype = ADDOP then begin
118             op := look.strattr[1];
119             match(ADDOP);
120             term;
121             if op = '+'
122                then WriteCode('ADD')   // Expr ==> Term + Term
123                else WriteCode('SUB');  // Expr ==> Term - Term
124          end
125          else exit;                    // Expr ==> Term
126       until 1+1=3;
127    end;
128 
129 procedure TParser.Term;
130    var op : char;
131 
132    begin
133       Factor;
134 
135       repeat
136          if look.tokentype = MULOP then begin
137             op := look.strattr[1];
138             match(MULOP);
139             factor;
140             if op = '*'
141                then WriteCode('MUL')   // Term ==> Fact * Fact
142                else WriteCode('DIV');  // Term ==> Fact / Fact
143          end
144          else exit;                    // Term ==> Fact
145       until 1+1=3;
146    end;
147 
148 procedure TParser.Factor;
149    var arg : string;
150 
151    begin
152       if look.tokentype = NUM then begin
153          arg := 'CONSTPUSH ' + floattostr(look.numattr);
154          WriteCode(arg);               // Fact ==> num
155          match(NUM);
156       end
157       else if look.tokentype = ID then begin
158          WriteCode('VARPUSH ' + look.strattr);
159          match(ID);                    // Fact ==> id
160       end
161       else if look.tokentype = OPBR then begin
162          match(OPBR);
163          expr;                         // Fact ==> ( Expr )
164          match(CLBR);
165       end
166       else begin
167          WriteError('<Factor> meldet Fehler!');
168          WriteError('Lookahead ist ' + TokenToStr(look.tokentype));
169          exit;
170       end;
171    end;
172 
173 procedure TParser.Parse;
174 {  Einstiegsroutine für die Klasse
175 }
176    begin
177       Lexer.GetNext(look);             // erstes Token holen
178       Expr;                            // Startsymbol aufrufen
179    end;
180 
181 
182 end.

