// Taschenrechner mit rekursivem Abstieg, Luxusversion
//
// Aufruf: rechner
// (der Input wird vom Terminal gelesen)
// 
// Klaus Kusche, 2010


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

// Setze das globale c auf das nächste "echte" Zeichen des Inputs
void nextc(void);
// Gib einen Syntaxfehler an der aktuellen Position aus und beende das Programm
void error(void);
// Lies einen Variablennamen (1 Kleinbuchstabe), liefere dessen Index
int getvar(void);
// Lies eine Gleitkomma-Zahl, ohne Vorzeichen
double value(void);
// Lies einen Operand: Zahl, Variable oder Klammerausdruck,
// |...| für Betrag und [...] für ganzzahliger Anteil,
// Sqrt(...) als Beispiel für eine Funktion,
// oder ! für letztes Ergebnis, E für Euler'sche Zahl, P für Pi
// Alles ev. mit - davor
double operand(void);
// Lies einen Faktor eines Produktes: Ein Operand oder eine Potenz
double factor(void);
// Lies einen Term einer Summe:
// Ein Faktor oder Produkt bzw. Quotient von Faktoren
double term(void);
// Lies einen Ausdruck: Ein Summand oder Summe bzw. Differenz von Summanden
double expr(void);
// Lies, berechne und drucke eine Zeile: Leer, Ausdruck oder Zuweisung
double line(void);


// Nächstes zu bearbeitendes Zeichen (int wegen EOF)
// Das ist unser "1 Zeichen LookAhead"
// Muss am Anfang '\n' sein, um das Lesen der ersten Zeile auszulösen
int c = '\n';
// Zeilen- und Spaltennummer (für Fehlermeldungen)
int lineNr = 0, colNr = 0;

// Speicher für die Variablen a-z
double var[26];

// Speicher für das Ergebnis der letzten Zeile
double lastVal;

// Setze das globale c auf das nächste "echte" Zeichen des Inputs:
// Überspringe Zwischenräume
// Am Ende des Files ist c die Konstante "EOF"
void nextc(void)
{
  if (c == '\n') {
    ++lineNr;
    colNr = 0;
  }
  do {
    c = getchar();
    ++colNr;
  }
  while ((c == ' ') || (c == '\t'));
}

// Gib einen Syntaxfehler an der aktuellen Position aus und beende das Programm
void error(void)
{
  if (c == EOF) {
    printf("Line %d: Parse error at end of input\n", lineNr);
  } else if (c == '\n') {
    printf("Line %d, col %d: Parse error at end of line\n", lineNr, colNr);
  } else {
    printf("Line %d, col %d: Parse error before %c\n", lineNr, colNr, c);
  }
  exit(EXIT_FAILURE);
}

// Lies einen Variablennamen (1 Kleinbuchstabe), liefere dessen Index
int getvar(void)
{
  int ind;

  if ((c < 'a') || (c > 'z')) {
    error();
  }
  ind = c - 'a';
  nextc();
  return ind;
}

// Lies eine Gleitkomma-Zahl, ohne Vorzeichen
// <value> ::= <digit> { <digit> } [ . { <digit> } ]
//             [ ( e | E ) [ + | - ] <digit> { < digit> } ]
double value(void)
{
  double val = 0;
  double frac = 0.1;
  int expon = 0;
  int esgn = 1;

  if (!isdigit(c)) {
    error();
  }
  do {
    val = val * 10 + (c - '0');
    nextc();
  } while (isdigit(c));
  if (c == '.') {
    nextc();
    while (isdigit(c)) {
      val += frac * (c - '0');
      frac /= 10;
      nextc();
    }
  }
  if ((c == 'e') || (c == 'E')) {
    nextc();
    if (c == '+') {
      nextc();
    } else if (c == '-') {
      esgn = -1;
      nextc();
    }
    if (!isdigit(c)) {
      error();
    }
    do {
      expon = expon * 10 + (c - '0');
      nextc();
    } while (isdigit(c));
    val *= pow(10.0, ((double) (esgn * expon)));
  }
  return val;
}

// Lies einen Operand: Zahl, Variable oder Klammerausdruck,
// |...| für Betrag und [...] für ganzzahliger Anteil,
// Sqrt(...) als Beispiel für eine Funktion,
// oder ! für letztes Ergebnis, E für Euler'sche Zahl, P für Pi
// Alles ev. mit - davor
// <operand> ::= [ - ] ( ! | E | P | Sqrt "(" <expr> ")" |
//                       "(" <expr> ")" | "|" <expr> "|" | "[" <expr> "]" |
//                       <value> | <var> )
double operand(void)
{
  double sgn = 1;
  double val;

  if (c == '-') {
    sgn = -1;
    nextc();
  }
  switch (c) {
    case '!':
      nextc();
      val = lastVal;
      break;
    case 'E':
      nextc();
      val = M_E;
      break;
    case 'P':
      nextc();
      val = M_PI;
      break;
    case 'S':
      nextc();
      if (c != 'q') {
        error();
      }
      nextc();
      if (c != 'r') {
        error();
      }
      nextc();
      if (c != 't') {
        error();
      }
      nextc();
      if (c != '(') {
        error();
      }
      nextc();
      val = expr();
      if (val < 0) {
        printf("Line %d, col %d: Negative square root (%g)\n",
               lineNr, colNr, val);
        exit(EXIT_FAILURE);
      }
      if (c != ')') {
        error();
      }
      nextc();
      val = sqrt(val);
      break;
    case '(':
      nextc();
      val = expr();
      if (c != ')') {
        error();
      }
      nextc();
      break;
    case '|':
      nextc();
      val = fabs(expr());
      if (c != '|') {
        error();
      }
      nextc();
      break;
    case '[':
      nextc();
      val = trunc(expr());
      if (c != ']') {
        error();
      }
      nextc();
      break;
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
      val = value();
      break;
    default:
      // es bleibt nur mehr die Möglichkeit einer Variable,
      // und wenn nicht, liefert getvar einen Fehler
      val = var[getvar()];
      break;
  }
  val *= sgn;
  return val;
}

// Lies einen Faktor eines Produktes: Ein Operand oder eine Potenz
// Achtung: ^ bindet von rechts nach links, darum Rekursion, nicht Schleife!
// <factor> ::= <operand> [ ^ <factor> ]
double factor(void)
{
  double val;

  val = operand();
  if (c == '^') {
    nextc();
    val = pow(val, factor());
  }
  return val;
}

// Lies einen Term einer Summe:
// Ein Faktor oder Produkt bzw. Quotient von Faktoren
// <term> ::= <factor> { ( * | / ) <factor> }
double term(void)
{
  int oper;
  double val, val1;

  val = factor();
  while ((c == '*') || (c == '/')) {
    oper = c;
    nextc();
    val1 = factor();
    if (oper == '*') {
      val *= val1;
    } else {
      if (val1 == 0) {
        printf("Line %d, col %d: Division by 0\n", lineNr, colNr);
        exit(EXIT_FAILURE);
      } else {
        val /= val1;
      }
    }
  }
  return val;
}

// Lies einen Ausdruck: Ein Summand oder Summe bzw. Differenz von Summanden
// <expr> ::= <term> { ( - | + ) <term> }
double expr(void)
{
  int oper;
  double val, val1;

  val = term();
  while ((c == '+') || (c == '-')) {
    oper = c;
    nextc();
    val1 = term();
    if (oper == '+') {
      val += val1;
    } else {
      val -= val1;
    }
  }
  return val;
}

// Lies, berechne und drucke eine Zeile: Leer, Ausdruck oder Zuweisung
// <line> ::= [ <expr> [ = <var> ] ]
double line(void)
{
  if (c != '\n') {
    lastVal = expr();
    if (c == '=') {
      nextc();
      var[getvar()] = lastVal;
    }
    printf("%.12g\n", lastVal);
  }
  return lastVal;
}

// Hauptprogramm: Berechne und drucke einen Ausdruck pro Zeile
// ev. mit Zuweisung
// <input> ::= { <line> \n } EOF
int main(void)
{
  nextc();
  while (c != EOF) {
    line();
    if (c != '\n') {
      error();
    }
    nextc();
  }

  exit(EXIT_SUCCESS);
}
