0

추가 나는 간단한 수학 파서 클래스를 찾았지만 같은 논리 연산, 또는 식을 지원하지 않습니다수학 파서 - 논리, 비교 및 ​​조건 연산자

: 여기
(a > b) ? (x^2) : (a/3.56) 

파서입니다 이 질문의 중간에
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Calcultra 
{ 
    class Parser 
    { 
     // The available operators for use in mathematical expressions. 
     private string[] _operators = { "-", "+", "/", "*", "^" }; 

     // The mathematical operations performed by the operators. 
     private Func<double, double, double>[] _operations = { 
      (a1, a2) => a1 - a2, 
      (a1, a2) => a1 + a2, 
      (a1, a2) => a1/a2, 
      (a1, a2) => a1 * a2, 
      (a1, a2) => Math.Pow(a1, a2) 
     }; 

     /** 
     * Parses and evaluates a mathematical expression and returns the result. 
     */ 
     public double Eval(string expression) 
     { 
      List<string> tokens = getTokens(expression); 
      Stack<double> operandStack = new Stack<double>(); 
      Stack<string> operatorStack = new Stack<string>(); 
      int tokenIndex = 0; 

      while (tokenIndex < tokens.Count) 
      { 
       string token = tokens[tokenIndex]; 

       if (token == "(") 
       { 
        string subExpr = getSubExpression(tokens, ref tokenIndex); 
        operandStack.Push(Eval(subExpr)); 
        continue; 
       } 

       if (token == ")") 
       { 
        throw new ArgumentException("Mis-matched parentheses in expression"); 
       } 

       // If this is an operator. 
       if (Array.IndexOf(_operators, token) >= 0) 
       { 
        while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek())) 
        { 
         string op = operatorStack.Pop(); 
         double arg2 = operandStack.Pop(); 
         double arg1 = operandStack.Pop(); 
         operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2)); 
        } 

        operatorStack.Push(token); 
       } 
       else 
       { 
        operandStack.Push(double.Parse(token)); 
       } 

       tokenIndex += 1; 
      } 

      while (operatorStack.Count > 0) 
      { 
       string op = operatorStack.Pop(); 
       double arg2 = operandStack.Pop(); 
       double arg1 = operandStack.Pop(); 
       operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2)); 
      } 

      return operandStack.Pop(); 
     } 

     /** 
     * Why even write a description for this function. 
     */ 
     private string getSubExpression(List<string> tokens, ref int index) 
     { 
      StringBuilder subExpr = new StringBuilder(); 
      int parenlevels = 1; 
      index += 1; 

      while (index < tokens.Count && parenlevels > 0) 
      { 
       string token = tokens[index]; 

       if (tokens[index] == "(") 
       { 
        parenlevels += 1; 
       } 

       if (tokens[index] == ")") 
       { 
        parenlevels -= 1; 
       } 

       if (parenlevels > 0) 
       { 
        subExpr.Append(token); 
       } 

       index += 1; 
      } 

      if ((parenlevels > 0)) 
      { 
       throw new ArgumentException("Mis-matched parentheses in expression"); 
      } 

      return subExpr.ToString(); 
     } 

     /** 
     * Tokenizes the given mathematical expression. 
     */ 
     private List<string> getTokens(string expression) 
     { 
      string operators = "()^*/+-"; 
      List<string> tokens = new List<string>(); 
      StringBuilder sb = new StringBuilder(); 

      foreach (char c in expression.Replace(" ", string.Empty)) 
      { 
       if (operators.IndexOf(c) >= 0) 
       { 
        if ((sb.Length > 0)) 
        { 
         tokens.Add(sb.ToString()); 
         sb.Length = 0; 
        } 

        tokens.Add(c.ToString()); 
       } 
       else 
       { 
        sb.Append(c); 
       } 
      } 

      if ((sb.Length > 0)) 
      { 
       tokens.Add(sb.ToString()); 
      } 

      return tokens; 
     } 
    } 
} 

나는 코드를 이해하기 위해 좀 더 노력하고, 정말 파악 주요 부분은 다음과 같습니다

// If this is an operator. 
if (Array.IndexOf(_operators, token) >= 0) 
{ 
    while (operatorStack.Count > 0 && Array.IndexOf(_operators, token) < Array.IndexOf(_operators, operatorStack.Peek())) 
    { 
     string op = operatorStack.Pop(); 
     double arg2 = operandStack.Pop(); 
     double arg1 = operandStack.Pop(); 
     operandStack.Push(_operations[Array.IndexOf(_operators, op)](arg1, arg2)); 
    } 

    operatorStack.Push(token); 
} 
else 
{ 
    operandStack.Push(double.Parse(token)); 
} 
,536,

나는 연산자를 확인하고, 인수 사이의 연산을 피연산자 스택에 푸시하는 것을 본다. 여기서 내가 조건문을 검사하는 곳이라고 생각하고, ?: 심볼을 확인하고, 3 개의 서브 표현식 모두를 얻고, 조건식을 평가하고 마지막 두 개의 서브 표현식 중 하나를 선택하여 피연산자 스택에 푸시해야합니다. 적어도 그것이 내가 그것을 이해하는 방법입니다. 나는 비록 비교에 관해서 해야할지 잘 모르겠다.

내가 비슷한 질문이 실현 : Adding Conditionals & Functions to a Math Parser

하지만 내 코드가 수행 뭐죠 적응하는 방법을 알아낼 수 없습니다 C# .NET을 사용하고 있습니다. 나는 당신이 나를위한 코드를 작성하는 것을 요구하지는 않는다. (많은 xP를 불평하지는 않을 것이지만) 나는 시작점이 정말로 필요하다. 이 작업을 수행하기 위해 수행해야 할 단계는 무엇입니까?

+0

대신 기본 컴파일러를 사용할 수 있습니다. [CodeDOM] (http://msdn.microsoft.com/en-us/library/650ax5cx (v = vs.110) .aspx) – Dmitry

답변

0

나는 이것을 시도하지는 않았지만 코드가 너무 복잡해 보이지 않으므로 직접 시도해야합니다. 디버거에서 Parse을 단계별로 실행 해보십시오. 당신이해야 할 것입니다

우선 _operators"<", "?"":" 같은 새로운 문자열을 추가하고 getTokens에서 그들을 찾을 수 있습니다. 또한 작업을 수행하는 _operationsFunc을 추가하십시오.

내가 처한 유일한 데이터 유형은 double이며, <과 같은 관계 연산자는 bool입니다. 0이 거짓이고 0이 아닌 것이 참인 이전 C 규칙을 사용할 수 있지만 구문 분석기가 형식이 없기 때문에주의해야합니다.

당신이 직면하게 될 다른로드 블록은 3 진 연산자 ?에 대한 인수가 토큰이 아닌 표현식이며 구문 분석기는 토큰 만 봅니다. 파스칼에서 각 표현식을 완전히 평가할 수있는 바로 가기를 사용할 수 있습니다. Eval을 수정하여 ?이 우선 순위가 가장 낮지 만 표현식에 : 앞에오고 정확히 Eval이 왼쪽에서 오른쪽으로 표시되어야합니다. IIRC Pascal은 내부적으로 표현식에 괄호를 추가하여 우선 순위를 처리하는 또 다른 단축키를 사용 했으므로, 예를 들어 1>0 ? 1+1 : 1-1(1>0)?((1+1):(1-1))이되면 2이되는 1?(2:0)이됩니다.

토큰이 아닌 Abstract Syntax Trees을 추가로 생산해야합니다.