(*---------------------------------------------------------------------------
  :Program.    Pute
  :Author.     Fridtjof Siebert
  :Address.    Nobileweg 67, D-7-Stgt-40
  :Phone.      (0)711/822509
  :Shortcut.   [fbs]
  :Version.    1.0
  :Date.       27-May-89
  :Copyright.  PD
  :Language.   Modula-II
  :Translator. M2Amiga v3.2d
  :Imports.    SmallInOut [fbs]
  :Usage.      Pute <Expression>
  :Contents.   Small CLI-Command to compute the result of an expression
  :Contents.   Symbols: Number | HexNumber | + | - | * | / | DIV | MOD | ( | )
  :Contents.   Number = 0-9{0-9}, HexNumber = 0-9{0-9A-F}H
---------------------------------------------------------------------------*)

MODULE Pute; (* $S- *)

FROM SYSTEM      IMPORT ADR;
FROM Arts        IMPORT Terminate, dosCmdBuf, dosCmdLen;
FROM SmallInOut  IMPORT WriteString, WriteInt, WriteHex, Write, WriteLn;

TYPE
  Symbol = (lparen,rparen,times,plus,minus,divide,div,mod,number,eof);
  String = ARRAY[0..79] OF CHAR;

VAR
  Sym: Symbol;
  Number: LONGINT;
  Char: CHAR;
  buffer: POINTER TO ARRAY [0..30000] OF CHAR;
  index: LONGINT;
  Identifier: String;

(*-------------------------------------------------------------------------*)

PROCEDURE ReadChar();

BEGIN
  IF index<dosCmdLen THEN
    Char := CAP(buffer^[index]); INC(index)
  ELSE Char := 0C END;
END ReadChar;

(*-------------------------------------------------------------------------*)

PROCEDURE Error;

BEGIN
  WriteString("Usage: PUTE <Expression>"); WriteLn; Terminate(0);
END Error;

(*-------------------------------------------------------------------------*)

PROCEDURE GetSym();

VAR
  digit: String;    (* used to read constant numbers *)
  cnt,i: INTEGER;
  x: POINTER TO LONGINT;

BEGIN
  WHILE (Char<=" ") AND (Char>0C) DO ReadChar END;
  CASE Char OF
  "A".."Z":
    cnt := 0;
    REPEAT
      Identifier[cnt] := Char; ReadChar;
      INC(cnt); IF cnt=80 THEN Error END;
    UNTIL (Char<"A") OR (Char>"Z");
    Identifier[cnt] := 0C;
    x := ADR(Identifier);
    IF    x^=44495600H THEN Sym := div
    ELSIF x^=4D4F4400H THEN Sym := mod
    ELSE Error END |
  "0".."9":
    cnt := 0;
    REPEAT
      digit[cnt] := Char;
      INC(cnt);
      IF cnt=80 THEN Terminate(0) END;
      ReadChar;
    UNTIL ((Char<"0") OR (Char>"9")) AND ((Char<"A") OR (Char>"Z"));
    Number := 0;
    IF digit[cnt-1]#"H" THEN
      FOR i:=0 TO cnt-1 DO
        IF digit[i]>"9" THEN Error END;
        Number := 10 * Number + ORD(digit[i]) - ORD("0");
      END;
    ELSE
      FOR i:=0 TO cnt-2 DO
        Number := 16 * Number + ORD(digit[i]);
        IF digit[i]>"F" THEN Error;
        ELSIF digit[i]>"9" THEN DEC(Number,55)
        ELSE DEC(Number,ORD("0")) END;
      END;
    END;
    Sym := number |
  "(": Sym := lparen;     ReadChar |
  ")": Sym := rparen;     ReadChar |
  "*": Sym := times;      ReadChar |
  "+": Sym := plus;       ReadChar |
  "-": Sym := minus;      ReadChar |
  "/": Sym := divide;     ReadChar |
  0C:  Sym := eof; |
  ELSE Error END;
END GetSym;

(*-------------------------------------------------------------------------*)

PROCEDURE Expression(): LONGINT;


  PROCEDURE Term(): LONGINT;

    PROCEDURE Factor(): LONGINT;
    VAR c: LONGINT;
    BEGIN
      CASE Sym OF number: c := Number; GetSym |
                  lparen: GetSym; c:=Expression();
                          IF Sym#rparen THEN Error END |
                  ELSE Error END;
      RETURN c;
    END Factor;

  VAR c: LONGINT;

  BEGIN
    c := Factor();
    LOOP
      CASE Sym OF
      times:      GetSym; c := c  *  Factor() |
      divide,div: GetSym; c := c DIV Factor() |
      mod:        GetSym; c := c MOD Factor() |
      ELSE EXIT END;
    END;
    RETURN c;
  END Term;

VAR
  addOperator: Symbol;
  c: LONGINT;

BEGIN
  addOperator := Sym;
  IF (addOperator=plus) OR (addOperator=minus) THEN GetSym END;
  c := Term();
  IF addOperator=minus THEN c := -c END;
  LOOP
    CASE Sym OF
    plus:  GetSym; INC(c,Term()) |
    minus: GetSym; DEC(c,Term()) |
    ELSE EXIT END;
  END;
  RETURN c;
END Expression;

BEGIN
  buffer := dosCmdBuf; Char := " "; GetSym;
  index := Expression(); WriteInt(index,11); WriteString(" = ");
  WriteHex(index,9); Write("H"); WriteLn;
END Pute.

