MODULE Scanner;

IMPORT F := FileSystem, R := Requests;

CONST
  program * =  0; var    * =  1; begin  * =  2;   (* Symbole von Mini *)
  end     * =  3; while  * =  4; do     * =  5;
  print   * =  6; comma  * =  7; equal  * =  8;
  plus    * =  9; minus  * = 10; ident  * = 11;
  const   * = 12; eof    * = 13;

  MaxIdLen * = 79;

TYPE Identifier * = ARRAY MaxIdLen+1 OF CHAR;

VAR
  source    * : F.File;     (* Quelltextdatei                         *)
  char        : CHAR;       (* zuletzt gelesenes Zeichen (0X bei EOF) *)
  sym       - : INTEGER;    (* das letzte Symbol (program, var, etc.) *)
  identifier- : Identifier; (* der Bezeichner bei sym=ident           *)
  constant  - : LONGINT;    (* die Konstante bei sym=const            *)

PROCEDURE GetChar;
BEGIN IF ~ F.Read(source,char) THEN char := 0X END END GetChar;

PROCEDURE GetSym*;
VAR i: INTEGER;
BEGIN
  WHILE (char>0X) & (char<=" ") DO GetChar END;    (* Space, LF, etc. *)
  CASE CAP(char) OF
  | "A".."Z":                        (* Bezeichner oder Schlüsselwort *)
      i := 0;
      REPEAT
        identifier[i] := char;
        INC(i);
        GetChar;
      UNTIL (i=MaxIdLen) OR (CAP(char)<"A") OR (CAP(char)>"Z");
      identifier[i] := 0X;
      IF    identifier = "PROGRAM" THEN sym := program
      ELSIF identifier = "VAR"     THEN sym := var
      ELSIF identifier = "BEGIN"   THEN sym := begin
      ELSIF identifier = "END"     THEN sym := end
      ELSIF identifier = "WHILE"   THEN sym := while
      ELSIF identifier = "DO"      THEN sym := do
      ELSIF identifier = "PRINT"   THEN sym := print
      ELSE
        sym := ident;          (* Kein Schlüsselwort, also Bezeichner *)
      END;
  | "0".."9":                                       (* Konstante Zahl *)
      constant := 0;
      REPEAT
        constant := 10*constant + ORD(char) - ORD("0"); GetChar;
      UNTIL (char<"0") OR (char>"9");
      sym := const;
  | "=": sym := equal; GetChar;                      (* Sonderzeichen *)
  | ",": sym := comma; GetChar;
  | "+": sym := plus ; GetChar;
  | "-": sym := minus; GetChar;
  | 0X : sym := eof;
  ELSE R.Fail("Unerwartetes Zeichen!") END;
END GetSym;

BEGIN char := " " END Scanner.
