//************************************************************ private uint getOperatorPriority(e_Oper op) { uint result = 0; if (op <= e_Oper.assign_power) { result = 1; } else if (op <= e_Oper.xor_word) { result = 2; } else if (op <= e_Oper.not_equal) { result = 3; } else if (op <= e_Oper.substract) { result = 4; } else if (op <= e_Oper.div_word) { result = 5; } else if (op <= e_Oper.unary_plus) { result = 6; } else if (op <= e_Oper.not_word) { result = 7; } else if (op <= e_Oper.power) { result = 8; } else { result = (uint)op; } return(result); }
//************************************************************ private void computeOperation(e_Oper operation, ref Stack <Object> operands, ref Stack <string> functions) { //-------------------------------------------------------- Func <Object, Object> varToValue = (Object x) => { if (x.type == Object.e_ObjectType.obj_varcall) { x = internal_memory.getVariable(x.StringValue); } return(x); }; //-------------------------------------------------------- // Handle function call if (operation == e_Oper.function_call) { if (functions.Count() == 0) { throw new mtseException("%%no_functions_provided"); } string s = functions.Pop(); callFunction(s, ref operands); } else { Object result = new Object(); bool unary_found = false; var arg2 = operands.Pop(); arg2 = varToValue(arg2); arg2.conditionalFloatToInt(); // At first, assignment operators if (getOperatorPriority(operation) == 1) { var arg1 = operands.Pop(); // Don't use varToValue() yet switch (operation) { case e_Oper.assign_noresult: result = compute_assign_noresult(arg1, arg2, ref internal_memory, ref __flag__constant_creating); break; case e_Oper.assign_result: result = compute_assign_result(arg1, arg2, ref internal_memory, ref __flag__constant_creating); break; case e_Oper.assign_add: result = compute_assign_add(arg1, arg2, ref internal_memory); break; case e_Oper.assign_substract: result = compute_assign_substract(arg1, arg2, ref internal_memory); break; case e_Oper.assign_multiply: result = compute_assign_multiply(arg1, arg2, ref internal_memory); break; case e_Oper.assign_divide: result = compute_assign_divide(arg1, arg2, ref internal_memory); break; case e_Oper.assign_power: result = compute_assign_power(arg1, arg2, ref internal_memory); break; default: break; } } else { // Unary operators switch (operation) { case e_Oper.unary_minus: result = compute_unary_minus(arg2); unary_found = true; break; case e_Oper.unary_plus: result = compute_unary_plus(arg2); unary_found = true; break; case e_Oper.not_word: result = compute_not_word(arg2); unary_found = true; break; default: break; } // Binary operators if (!unary_found) { var arg1 = operands.Pop(); arg1 = varToValue(arg1); arg1.conditionalFloatToInt(); switch (operation) { case e_Oper.or_word: result = compute_or_word(arg1, arg2); break; case e_Oper.and_word: result = compute_and_word(arg1, arg2); break; case e_Oper.xor_word: result = compute_xor_word(arg1, arg2); break; case e_Oper.less: result = compute_less(arg1, arg2); break; case e_Oper.greater: result = compute_greater(arg1, arg2); break; case e_Oper.equal: result = compute_equal(arg1, arg2); break; case e_Oper.less_equal: result = compute_less_equal(arg1, arg2); break; case e_Oper.greater_equal: result = compute_greater_equal(arg1, arg2); break; case e_Oper.not_equal: result = compute_not_equal(arg1, arg2); break; case e_Oper.add: result = compute_add(arg1, arg2); break; case e_Oper.substract: result = compute_substract(arg1, arg2); break; case e_Oper.multiply: result = compute_multiply(arg1, arg2); break; case e_Oper.divide: result = compute_divide(arg1, arg2); break; case e_Oper.mod_word: result = compute_mod_word(arg1, arg2); break; case e_Oper.div_word: result = compute_div_word(arg1, arg2); break; case e_Oper.power: result = compute_power(arg1, arg2); break; default: throw new mtseException("%%unknown_operator"); } } } operands.Push(result); } }
//************************************************************ public void analyze() { code_result = new Object(); // To begin with, remove comment and white chars //if (content.Length != 1 || soal.belongsTo(content[0], soal.e_CharGroup.white_chars)) if (String.IsNullOrEmpty(content)) { return; } content = soal.trimOffGivenChars(content, soal.e_CharGroup.white_chars); int comment_start = 0; uint apostrophes = 0; while (comment_start < content.Length) { if (content[comment_start] == '#' && apostrophes % 2 == 0) { content = content.Substring(0, comment_start); break; } else if (content[comment_start] == '\'') { ++apostrophes; } ++comment_start; } //outOfTheLoop if (String.IsNullOrEmpty(content)) { return; } //-------------------------------------------------- Stack <Object> object_stack = new Stack <Object>(); //objects, values found in code Stack <e_Oper> operator_stack = new Stack <e_Oper>(); //operators found in code Stack <string> function_stack = new Stack <string>(); //names of functions to be called __flag__constant_creating = false; position = 0; Token t = getNextToken(); while (t.type != Token.e_TokenType.eol_tkn) { switch (t.type) { //* * * * * * * * * * * * * * * * * * * * * * * case Token.e_TokenType.value_tkn: { Object x = new mtse.Object((Object.e_ObjectType)t.value[0]); string s = t.value.Substring(1); switch (x.type) { case Object.e_ObjectType.obj_int: x.IntValue = Int64.Parse(s); break; case Object.e_ObjectType.obj_float: x.FloatValue = Double.Parse(s, CultureInfo.InvariantCulture); break; case Object.e_ObjectType.obj_string: x.StringValue = s; break; // 'default' condition isn't supposed to happen default: throw new mtseException("%%unexpected_value_token"); } object_stack.Push(x); break; } //* * * * * * * * * * * * * * * * * * * * * * * case Token.e_TokenType.operator_tkn: { _operator_analysis: e_Oper x = (e_Oper)t.value[0]; // Handle right parenthesis - compute all between '(' and ')' if (x == e_Oper.right_parenth) { while (operator_stack.Peek() != e_Oper.left_parenth && operator_stack.Peek() != e_Oper.function_call) { computeOperation(operator_stack.Pop(), ref object_stack, ref function_stack); } switch (operator_stack.Peek()) { case e_Oper.left_parenth: operator_stack.Pop(); break; case e_Oper.function_call: { operator_stack.Pop(); callFunction(function_stack.Pop(), ref object_stack); break; } default: throw new mtseException("%%right_parenth_lacks_left_parenth"); } } else if (x == e_Oper.comma) { if (operator_stack.Count() == 0) { throw new mtseException("%%not_enough_args_provided"); //should be already handled in getNextToken() } while (operator_stack.Peek() != e_Oper.left_parenth && operator_stack.Peek() != e_Oper.function_call) { computeOperation(operator_stack.Pop(), ref object_stack, ref function_stack); } } else if (operator_stack.Count() == 0 || getOperatorPriority(x) > getOperatorPriority(operator_stack.Peek()) || operator_stack.Peek() == e_Oper.left_parenth || operator_stack.Peek() == e_Oper.function_call || getOperatorPriority(x) == 6 || getOperatorPriority(x) == 7) { operator_stack.Push(x); } else { // Compute last operations on the stack // with greater priority than 'x' computeOperation(operator_stack.Pop(), ref object_stack, ref function_stack); goto _operator_analysis; } break; } //* * * * * * * * * * * * * * * * * * * * * * * case Token.e_TokenType.function_tkn: { Object obj = new Object(Object.e_ObjectType.obj_arg_limiter); object_stack.Push(obj); operator_stack.Push(e_Oper.function_call); function_stack.Push(t.value); break; } //* * * * * * * * * * * * * * * * * * * * * * * case Token.e_TokenType.variable_tkn: { // Handle keywords if (t.value == "const") { // Create a constant if (__flag__constant_creating) { throw new mtseException("%%const_repetition"); } else { __flag__constant_creating = true; } } else { Object obj = new Object(Object.e_ObjectType.obj_varcall); obj.StringValue = t.value; object_stack.Push(obj); } break; } //* * * * * * * * * * * * * * * * * * * * * * * case Token.e_TokenType.eol_tkn: break; } t = getNextToken(); } // End Of Line (EOL) while (operator_stack.Count() != 0) { computeOperation(operator_stack.Pop(), ref object_stack, ref function_stack); } // Eventually, operator_stack ought to contain no elements, // and object_stack - 1 element. Different state occurs when // user's code syntax is incorrect if (operator_stack.Count() != 0 || object_stack.Count() > 1) { throw new mtseException("%%incorrect_syntax"); } if (object_stack.Count() == 0) { Object x = new Object(Object.e_ObjectType.obj_void); object_stack.Push(x); } this.code_result = object_stack.Pop(); if (code_result.type == Object.e_ObjectType.obj_varcall) { code_result = internal_memory.getVariable(code_result.StringValue); } }