// singleton class, no sense making many instaces of the language public static MiniPL GetInstance() { if (instance == null) { instance = new MiniPL(); } return(instance); }
// the expected return type of the operation public override ValueType Type(MiniPL.Runnable context) { switch (op) { case '+': ValueType t = lhs.Type(context); if (t == ValueType.String) return t; return ValueType.Integer; case '-': return ValueType.Integer; case '*': return ValueType.Integer; case '/': return ValueType.Integer; case '<': return ValueType.Boolean; case '=': return ValueType.Boolean; case '&': return ValueType.Boolean; default: throw new Exception("UNEXPECTER OPERATOR " + op); } }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // print value of parameter to output stream switch (expr.Type(context)) { case ValueType.Integer: stdout.Write(expr.Evaluate(context).IntValue()); break; case ValueType.String: stdout.Write(expr.Evaluate(context).StringValue()); break; default: throw new Exception("TYPE CHECK FAILED"); } return null; }
// Execute read statement public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // read whitespace-delimited token from input stream string input = ""; char[] buf = new char[1]; // works well enough for console input but surely there's a better way.. while (true) { int read = stdin.Read(buf, 0, 1); if (read == 0) break; if (buf[0] == ' ' || buf[0] == '\t' || buf[0] == '\n') break; input += buf[0]; } if (context.declarations[identifier].Type == ValueType.Integer) { // if expecting integer but parsing fails, create runtime error int inputInt = 0; if (!Int32.TryParse(input, out inputInt)) return new RuntimeError(Token, "expected to read integer"); context.values[identifier] = new Value(inputInt); } else if (context.declarations[identifier].Type == ValueType.String) { context.values[identifier] = new Value(input); } else throw new Exception("TYPE CHECKING FAILED"); return null; }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // update symbol table to default or specified initial value context.values[identifier] = (initialValue == null) ? new Value(type) : initialValue.Evaluate(context); return null; }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // execute all statements in block for every value of control variable from // value of start expression to value of end expression (inclusive) int start = startVal.Evaluate(context).IntValue(); int end = endVal.Evaluate(context).IntValue(); for (int i = start; i <= end; i++) { context.values[identifier] = new Value(i); foreach (Statement stmt in block) { stmt.Execute(context, stdin, stdout); } } // sample code seemed to indicate control value should be end + 1 after execution context.values[identifier] = new Value(end + 1); return null; }
public override void TypeCheck(MiniPL.Runnable context) { expr.TypeCheck(context); if (expr.Type(context) != ValueType.Boolean && expr.Type(context) != ValueType.Integer) context.errors.Add(new SemanticError(Token, "bad type for '!' operation")); }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { // just update symbol table context.values[identifier] = expr.Evaluate(context); return null; }
public override Value Evaluate(MiniPL.Runnable context) { if (op == '!') { if (expr.Type(context) == ValueType.Boolean) return new Value(!expr.Evaluate(context).BooleanValue()); if (expr.Type(context) == ValueType.Integer) return new Value(expr.Evaluate(context).IntValue() == 0); throw new Exception("TYPE CHECKING FAILED"); } throw new Exception("UNEXPECTED OPERATION " + op); }
public override ValueType Type(MiniPL.Runnable context) { return ValueType.Boolean; }
public override ValueType Type(MiniPL.Runnable context) { return context.declarations[identifier].Type; }
public override Value Evaluate(MiniPL.Runnable context) { return context.values[identifier]; }
// recursively check operands and check that their types are compatible with operation public override void TypeCheck(MiniPL.Runnable context) { rhs.TypeCheck(context); lhs.TypeCheck(context); switch (op) { case '+': if (!((rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer) || (rhs.Type(context) == ValueType.String && lhs.Type(context) == ValueType.String))) context.errors.Add(new SemanticError(Token, "bad operand types for '+' operation")); break; case '-': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) context.errors.Add(new SemanticError(Token, "bad operand types for '-' operation")); break; case '*': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) context.errors.Add(new SemanticError(Token, "bad operand types for '*' operation")); break; case '/': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) context.errors.Add(new SemanticError(Token, "bad operand types for '/' operation")); break; case '<': if (!(rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer)) context.errors.Add(new SemanticError(Token, "bad operand types for '<' operation")); break; case '=': if (!(rhs.Type(context) == lhs.Type(context))) context.errors.Add(new SemanticError(Token, "bad operand types for '=' operation")); break; case '&': if (rhs.Type(context) == ValueType.String || lhs.Type(context) == ValueType.String) context.errors.Add(new SemanticError(Token, "bad operand types for '&' operation")); break; } }
public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout) { if (expr.Type(context) == ValueType.String) throw new Exception("TYPE CHECKING FAILED"); // if expression evaluates to false, stop execution with a runtime error if (expr.Evaluate(context).BooleanValue() == false) return new RuntimeError(Token, "assertion failed"); return null; }
public override Value Evaluate(MiniPL.Runnable context) { return value; }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameter expr.TypeCheck(context); // only defined for boolean parameter, but we'll allow integers too.. if (expr.Type(context) == ValueType.String) context.errors.Add(new SemanticError(Token, "cannot assert a string value")); }
public override ValueType Type(MiniPL.Runnable context) { return value.Type(); }
public override void TypeCheck(MiniPL.Runnable context) { // typecheck value expr.TypeCheck(context); // check that value type matches variable switch (context.declarations[identifier].Type) { case ValueType.Boolean: if (expr.Type(context) == ValueType.String) context.errors.Add(new SemanticError(Token, "cannot assign string value to boolean " + identifier)); break; case ValueType.Integer: if (expr.Type(context) != ValueType.Integer) context.errors.Add(new SemanticError(Token, "expected integer type value for " + identifier)); break; case ValueType.String: if (expr.Type(context) != ValueType.String) context.errors.Add(new SemanticError(Token, "expected string type value for " + identifier)); break; } }
public override void TypeCheck(MiniPL.Runnable context) { // nothing to check }
public override void TypeCheck(MiniPL.Runnable context) { // if initial value specified check it agaist the type if (initialValue != null) { initialValue.TypeCheck(context); switch (type) { case ValueType.Boolean: if (initialValue.Type(context) == ValueType.String) context.errors.Add(new SemanticError(Token, "cannot assign string value to boolean " + identifier)); break; case ValueType.Integer: if (initialValue.Type(context) != ValueType.Integer) context.errors.Add(new SemanticError(Token, "expected integer type value for " + identifier)); break; case ValueType.String: if (initialValue.Type(context) != ValueType.String) context.errors.Add(new SemanticError(Token, "expected string type value for " + identifier)); break; } } }
public abstract Value Evaluate(MiniPL.Runnable context);
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameters, control variable, and every statement in loop startVal.TypeCheck(context); endVal.TypeCheck(context); if (context.declarations[identifier].Type != ValueType.Integer) context.errors.Add(new SemanticError(Token, "bad for-loop control type")); if (startVal.Type(context) != ValueType.Integer) context.errors.Add(new SemanticError(startVal.Token, "bad for-loop start value type")); if (endVal.Type(context) != ValueType.Integer) context.errors.Add(new SemanticError(startVal.Token, "bad for-loop end value type")); foreach (Statement stmt in block) { stmt.TypeCheck(context); } }
public abstract ValueType Type(MiniPL.Runnable context);
public override void TypeCheck(MiniPL.Runnable context) { // typecheck parameter expr.TypeCheck(context); // Mini-PL spec only defines print for integer and boolean values if (expr.Type(context) == ValueType.Boolean) context.errors.Add(new SemanticError(Token, "cannot print a boolean value")); }
public abstract RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout);
// Mini-PL spec only defines reading integer and string values public override void TypeCheck(MiniPL.Runnable context) { if (context.declarations[identifier].Type == ValueType.Boolean) context.errors.Add(new SemanticError(Token, "cannot read a boolean value")); }
public abstract void TypeCheck(MiniPL.Runnable context);
// singleton class, no sense making many instaces of the language public static MiniPL GetInstance() { if (instance == null) instance = new MiniPL(); return instance; }
// apply the appropriate operation on operands public override Value Evaluate(MiniPL.Runnable context) { switch (op) { case '+': if (rhs.Type(context) == ValueType.Integer && lhs.Type(context) == ValueType.Integer) return new Value(lhs.Evaluate(context).IntValue() + rhs.Evaluate(context).IntValue()); if (rhs.Type(context) == ValueType.String && lhs.Type(context) == ValueType.String) return new Value(lhs.Evaluate(context).StringValue() + rhs.Evaluate(context).StringValue()); throw new Exception("TYPECHECKING FAILED"); case '-': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) throw new Exception("TYPECHECKING FAILED"); return new Value(lhs.Evaluate(context).IntValue() - rhs.Evaluate(context).IntValue()); case '*': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) throw new Exception("TYPECHECKING FAILED"); return new Value(lhs.Evaluate(context).IntValue() * rhs.Evaluate(context).IntValue()); case '/': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) throw new Exception("TYPECHECKING FAILED"); int denominator = rhs.Evaluate(context).IntValue(); if (denominator == 0) throw new MiniPL_DivideByZeroException(new RuntimeError(Token, "divide by zero")); return new Value(lhs.Evaluate(context).IntValue() / denominator); case '<': if (rhs.Type(context) != ValueType.Integer || lhs.Type(context) != ValueType.Integer) throw new Exception("TYPECHECKING FAILED"); return new Value(lhs.Evaluate(context).IntValue() < rhs.Evaluate(context).IntValue()); case '=': if (rhs.Type(context) != lhs.Type(context)) throw new Exception("TYPECHECKING FAILED"); switch (rhs.Type(context)) { case ValueType.Boolean: return new Value(rhs.Evaluate(context).BooleanValue() == lhs.Evaluate(context).BooleanValue()); case ValueType.Integer: return new Value(rhs.Evaluate(context).IntValue() == lhs.Evaluate(context).IntValue()); case ValueType.String: return new Value(rhs.Evaluate(context).StringValue() == lhs.Evaluate(context).StringValue()); } break; case '&': if (rhs.Type(context) == ValueType.String || lhs.Type(context) == ValueType.String) throw new Exception("TYPECHECKING FAILED"); return new Value(rhs.Evaluate(context).BooleanValue() && lhs.Evaluate(context).BooleanValue()); } throw new Exception("UNEXPECTED OPERATOR " + op); }