예제 #1
0
 // singleton class, no sense making many instaces of the language
 public static MiniPL GetInstance()
 {
     if (instance == null)
     {
         instance = new MiniPL();
     }
     return(instance);
 }
예제 #2
0
 // 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);
     }
 }
예제 #3
0
 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;
 }
예제 #4
0
            // 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;
            }
예제 #5
0
 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;
 }
예제 #6
0
            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;
            }
예제 #7
0
 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"));
 }
예제 #8
0
 public override RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout)
 {
     // just update symbol table
     context.values[identifier] = expr.Evaluate(context);
     return null;
 }
예제 #9
0
 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);
 }
예제 #10
0
 public override ValueType Type(MiniPL.Runnable context)
 {
     return ValueType.Boolean;
 }
예제 #11
0
 public override ValueType Type(MiniPL.Runnable context)
 {
     return context.declarations[identifier].Type;
 }
예제 #12
0
 public override Value Evaluate(MiniPL.Runnable context)
 {
     return context.values[identifier];
 }
예제 #13
0
 // 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;
     }
 }
예제 #14
0
 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;
 }
예제 #15
0
 public override Value Evaluate(MiniPL.Runnable context)
 {
     return value;
 }
예제 #16
0
 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"));
 }
예제 #17
0
 public override ValueType Type(MiniPL.Runnable context)
 {
     return value.Type();
 }
예제 #18
0
 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;
     }
 }
예제 #19
0
 public override void TypeCheck(MiniPL.Runnable context)
 {
     // nothing to check
 }
예제 #20
0
 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;
         }
     }
 }
예제 #21
0
 public abstract Value Evaluate(MiniPL.Runnable context);
예제 #22
0
 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);
     }
 }
예제 #23
0
 public abstract ValueType Type(MiniPL.Runnable context);
예제 #24
0
 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"));
 }
예제 #25
0
 public abstract RuntimeError Execute(MiniPL.Runnable context, TextReader stdin, TextWriter stdout);
예제 #26
0
 // 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"));
 }
예제 #27
0
 public abstract void TypeCheck(MiniPL.Runnable context);
예제 #28
0
 // singleton class, no sense making many instaces of the language
 public static MiniPL GetInstance()
 {
     if (instance == null)
         instance = new MiniPL();
     return instance;
 }
예제 #29
0
 // 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);
 }