Написать синтаксический анализатор-калькулятор - C#

Узнай цену своей работы

Формулировка задачи:

Задача заключается в том что надо написать программу "калькулятор" на языке С Sharp. Калькулятор должен уметь синтаксически анализировать выражения: вычитание, сложение, умножение, тангенс, синус и действительные числа. Подскажите пожалуйста советами или примерами, где можно найти информацию на эту задачу.

Решение задачи: «Написать синтаксический анализатор-калькулятор»

textual
Листинг программы
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace CalcTrans
{
    class Program
    {
        static void Main(string[] args)
        {
            string expr;
            Parser p = new Parser();
 
            Console.WriteLine("Для выхода из программы введите пустое выражение. ");
 
            for (; ; )
            {
                Console.Write("Введите выражение: ");
                expr = Console.ReadLine();
                if (expr == "") break;
                Console.WriteLine("Результат: " + p.Evaluate(expr));
            } 
        }
        //класс исключающий для ошибок для анализатора
        class ParserException : ApplicationException
        {
            public ParserException(string str) : base(str) { }
            public override string ToString()
            { return Message; }
        }
 
        class Parser
        {
            //перчисляем типы лексем.
            enum Types { NONE, DELIMITER, VARIABLE, NUMBER };
            // Перечисляем типы ошибок.
            enum Errors { SYNTAX, UNBALPARENS, NOEXP, DIVBYZERO };
 
            string exp; // Ссылка на строку выражения,
            int expIdx; // Текущий индекс в выражении,
            string token; // Текущая лексема.
            Types tokType; // Тип лексемы.
 
            // Массив для переменных,
            double[] vars = new double[26];
 
            public Parser()
            {
                // Инициализируем переменные нулевыми значениями.
                for (int i = 0; i < vars.Length; i++)
                    vars[i] = 0.0;
            }
            // Входная точка анализатора.
            public double Evaluate(string expstr)
            {
                double result;
                exp = expstr;
                expIdx = 0;
                try
                {
                    GetToken();
                    if (token == "")
                    {
                        SyntaxErr(Errors.NOEXP); // Выражение отсутствует,
                        return 0.0;
                    }
                    EvalExp1(out result); // В этом варианте анализатора
                    // сначала вызывается
                    // метод EvalExpl().
                    if (token != "") // Последняя лексема должна
                        // быть нулевой.
                        SyntaxErr(Errors.SYNTAX);
                    return result;
                }
                catch (ParserException exc)
                {
                    // При желании добавляем здесь обработку ошибок.
                    Console.WriteLine(exc);
                    return 0.0;
                }
            }
 
            // Обрабатываем присвоение,
            void EvalExp1(out double result)
            {
                int varIdx;
                Types ttokType;
                string temptoken;
                if (tokType == Types.VARIABLE)
                {
                    // Сохраняем старую лексему,
                    temptoken = String.Copy(token);
                    ttokType = tokType;
                    // Вычисляем индекс переменной,
                    varIdx = Char.ToUpper(token[0]) - 'A';
                    GetToken();
                    if (token != "=")
                    {
                        PutBack();// Возвращаем текущую лексему в поток
                        //и восстанавливаем старую,
                        // поскольку отсутствует присвоение.
                        token = String.Copy(temptoken);
                        tokType = ttokType;
                    }
                    else
                    {
                        GetToken();// Получаем следующую часть
                        // выражения ехр.
                        EvalExp2(out result);
                        vars[varIdx] = result;
                        return;
                    }
                }
 
                EvalExp2(out result);
            }
 
            // Складываем или вычитаем два члена выражения.
            void EvalExp2(out double result)
            {
                string op;
                double partialResult;
 
                EvalExp3(out result);
                while ((op = token) == "+" || op == "-")
                {
                    GetToken();
                    EvalExp3(out partialResult);
                    switch (op)
                    {
                        case "-":
                            result = result - partialResult;
                            break;
                        case "+":
                            result = result + partialResult;
                            break;
                    }
                }
            }
 
            // Выполняем умножение или деление двух множителей.
            void EvalExp3(out double result)
            {
                string op;
                double partialResult = 0.0;
                EvalExp4(out result);
                while ((op = token) == "*" || op == "/" || op == "%")
                {
                    GetToken();
                    EvalExp4(out partialResult);
                    switch (op)
                    {
                        case "*":
                            result = result * partialResult;
                            break;
                        case "/":
                            if (partialResult == 0.0)
                                SyntaxErr(Errors.DIVBYZERO);
                            result = result / partialResult;
                            break;
                        case "%":
                            if (partialResult == 0.0)
                                SyntaxErr(Errors.DIVBYZERO);
                            result = (int)result % (int)partialResult;
                            break;
                    }
                }
            }
 
            // выполняем возведение в степень
            void EvalExp4(out double result)
            {
                double partialResult, ex;
                int t;
                EvalExp5(out result);
                if (token == "^")
                {
                    GetToken();
                    EvalExp4(out partialResult);
                    ex = result;
                    if (partialResult == 0.0)
                    {
                        result = 1.0;
                        return;
                    }
                    for (t = (int)partialResult - 1; t > 0; t--)
                        result = result * (double)ex;
                }
            }
            // Выполненяем операцию унарного + или -.
            void EvalExp5(out double result)
            {
                string op;
 
                op = "";
                if ((tokType == Types.DELIMITER) && token == "+" || token == "-")
                {
                    op = token;
                    GetToken();
                }
                EvalExp6(out result);
                if (op == "-") result = -result;
            }
 
            // обрабатываем выражение в круглых скобках
            void EvalExp6(out double result)
            {
                if ((token == "("))
                {
                    GetToken();
                    EvalExp2(out result);
                    if (token != ")")
                        SyntaxErr(Errors.UNBALPARENS);
                    GetToken();
                }
                else Atom(out result);
            }
            // Получаем значение числа или переменной.
            void Atom(out double result)
            {
                switch (tokType)
                {
                    case Types.NUMBER:
                        try
                        {
                            result = Double.Parse(token);
                        }
                        catch (FormatException)
                        {
                            result = 0.0;
                            SyntaxErr(Errors.SYNTAX);
                        }
                        GetToken();
                        return;
                    case Types.VARIABLE:
                        result = FindVar(token);
                        GetToken();
                        return;
                    default:
                        result = 0.0;
                        SyntaxErr(Errors.SYNTAX);
                        break;
                }
            }
            // Возвращаем значение переменной.
            double FindVar(string vname)
            {
                if (!Char.IsLetter(vname[0]))
                {
                    SyntaxErr(Errors.SYNTAX);
                    return 0.0;
                }
                return vars[Char.ToUpper(vname[0]) - 'A'];
            }
            // Возвращаем лексему во входной поток.
            void PutBack()
            {
                for (int i = 0; i < token.Length; i++) expIdx--;
            }
            // Обрабатываем синтаксическую ошибку
            void SyntaxErr(Errors error)
            {
                string[] err ={
                         "Синтаксическая оошибка",
                         "Дисбаланс скобок",
                         "Выражение отсутствет",
                         "Деление на нуль"};
                throw new ParserException(err[(int)error]);
            }
            // получем следующую лексему.
            void GetToken()
            {
                tokType = Types.NONE;
                token = "";
                if (expIdx == exp.Length) return; // Конец выражения.
                // Опускаем пробел.
                while (expIdx < exp.Length && Char.IsWhiteSpace(exp[expIdx])) ++expIdx;
                // Хвостовой пробел завершает выражение.
                if (expIdx == exp.Length) return;
                if (IsDelim(exp[expIdx]))
                {
                    token += exp[expIdx];
                    expIdx++;
                    tokType = Types.DELIMITER;
                }
                else if (Char.IsLetter(exp[expIdx]))
                {
                    // Это переменная?
                    while (!IsDelim(exp[expIdx]))
                    {
                        token += exp[expIdx];
                        expIdx++;
                        if (expIdx >= exp.Length) break;
                    }
                    tokType = Types.VARIABLE;
                }
                else if (Char.IsDigit(exp[expIdx]))
                {
                    // Это число?
                    while (!IsDelim(exp[expIdx]))
                    {
                        token += exp[expIdx];
                        expIdx++;
                        if (expIdx >= exp.Length) break;
                    }
                    tokType = Types.NUMBER;
                }
            }
            // Метод возвращает значение true,
            // если с -- разделитель.
            bool IsDelim(char c)
            {
                if (("+-/*%^=()".IndexOf(c) != -1))
                    return true;
                return false;
            }
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

8   голосов , оценка 4.25 из 5
Похожие ответы