Week 7: Lecture/tutorial examples

rational number class with exception handling

class Rational {
  int num, denom;
  
  Rational(int num, int denom) {
    if (denom == 0)
      throw new ArgumentException("zero denominator");
      
    this.num = num; this.denom = denom;
  }
  
  public static Rational parse(string s) {
    string[] a = s.Split('/');
    if (a.Length != 2)
      throw new ArgumentException("rational must contain one slash");
      
    if (!int.TryParse(a[0], out int num) || !int.TryParse(a[1], out int denom))
      throw new ArgumentException("can't parse numerator or denominator");
      
    return new Rational(num, denom);
  }
  
  public override string ToString() => @"${num}/${denom}";
  
  public Rational reciprocal() {
    if (num == 0)
      throw new DivideByZeroException();

    return new Rational(denom, num);
  }
  
  public static void allReciprocal() {
    StreamReader reader;
    try {
      reader = new StreamReader("numbers");
    } catch (FileNotFoundException) {
      WriteLine("can't find input file!");
      return;
    }
    
    try {
      while (ReadLine() is string s) {
        try {
          WriteLine(parse(s).reciprocal());
        } catch (ArgumentException e) {
          WriteLine("warning: " + e.Message);
        } catch (DivideByZeroException) {
          WriteLine("warning: can't take reciprocal of zero");
        }
      }
    } finally {
      reader.Close();
    }
  }
}

representing algebraic expressions, continued

abstract class Expression {
  static void error() => throw new Exception("parse error");
  
  static char next(TextReader r) {
    int i = r.Read();
    if (i == -1) error();
    return (char) i;
  }
  
  // grammar:
  //
  // digit = '0' | '1' | ... | '9'
  // op = '+' | '-' | '*' | '/'
  // expr = digit +
  //      | '(' expr op expr ')'
  
  static Expression parse(TextReader r) {
    char c = next(r);
    if (char.IsDigit(c)) {
      string s = "";
      while (char.IsDigit((char) r.Peek()))
        s += (char) r.Read();
      return new IntExpr(int.Parse(s));
    }

    if (c != '(') error();
    Expression e = parse(r);
    char op = next(r);
    if ("+-*/".IndexOf(op) < 0)
      error();
    Expression f = parse(r);
    if (next(r) != ')') error();

    return new OpExpr(e, op, f);
  }
  
  public static Expression parse(string s) => parse(new StringReader(s));
  
  public abstract int depth();
}

class IntExpr : Expression {
  public int i;
  public IntExpr(int i) { this.i = i; }
  
  public override int depth() => 0;
}

class OpExpr : Expression {
  public char op;
  public Expression left, right;
  public OpExpr(Expression left, char op, Expression right) {
    this.left = left; this.op = op; this.right = right;
  }
  
  public override int depth() =>
    Max(left.depth(), right.depth()) + 1;
}

appending to a linked list, recursively

class Node {
  public readonly int i;
  public Node next;
    
  public Node(int i, Node next) { this.i = i; this.next = next; }
}

class Linked {
  Node head;
  
  public void insert(int i) {
    head = new Node(i, head);
  }
  
  static void append(int i, ref Node n) {
    if (n == null)
      n = new Node(i, null);
    else append(i, ref n.next);
  }
  
  public void append(int i) => append(i, ref head); 
}