Expression.h
#ifndef EXPRESSION_H
#define EXPRESSION_H
#include <cmath>
#include <string>
#include <cstring>
#pragma once
class Expression
{
private:
struct sintElem {
char lexeme;
double number;
};
double * numArray;
sintElem* walkthroughArray;/*Массив в котором хранятся результаты предразбора строки.
Признаком конца такого массива является walkthroughArray[i].lexeme == 127*/
sintElem* start;/*Хранит ссылку на первый элемент массива walkthroughArray
чтобы восстановить её после исполнения вычислительной части*/
//Функции конструктора. Подробные коментарии указаны в теле функций.
/*Функции хранящиеся в файле ArifmometrSortSigment.
Комплекс функций необходим для сортировки в польскую нотацию*/
void sortPoland (sintElem*);
void recursionMain (sintElem*,short&,short&);
void recursionPlus (sintElem*,short&,short&);
void recursionMult (sintElem*,short&,short&);
void recursionPow (sintElem*,short&,short&);
void recursionUnary(sintElem*,short&,short&);
/*Функции хранящиеся в файле ArifmometrPreparationSigment.
Комплекс функция необходимых для полготовки строки к сортировке в польскую нотацию*/
void sintAdaptation (char*);
double setPoint (double, short);
static char* addMult (char*);
sintElem* setArray (char*);
static void addCode (char*);
static inline bool isNumber(char);
static inline bool isLetter(char);
static inline char* argTest(char*);
static inline bool isUnary(char);
sintElem doIt(char,sintElem);
sintElem doIt(char,sintElem,sintElem);
static bool isOperation(char);
unsigned operatorCount(sintElem*);
void delElements(sintElem*, unsigned);
public:
Expression();
Expression(const Expression&);
Expression(char*);
Expression(const std::string&);
Expression& rebild(const std::string&);
Expression& rebild(const char*);
~Expression(void);
static bool isExp(const std::string&);
static bool isExp(const char*);
//Функции выдающие результат вычисления
double calculate ();
double calculate (double);
double calculate (double,double);
Expression& optimization ();
};
#endif // EXPRESSION_H
Expression.cpp
#include "stdafx.h"
#include <cmath>
#include "Expression.h"
#include <iostream>
Expression::Expression()
: walkthroughArray(0)
, numArray(0)
{
rebild("0");
|
}
Expression::Expression(char* expression)
: walkthroughArray(0)
, numArray(0)
{
rebild(expression);
}
Expression::Expression(const std::string& expression)
: walkthroughArray(0)
, numArray(0)
{
rebild(expression.c_str());
}
Expression::Expression(const Expression& copy)
{
size_t sizeOfArr = 0;
while(copy.walkthroughArray[sizeOfArr].lexeme!= 127)
++sizeOfArr;
walkthroughArray = new sintElem [sizeOfArr + 1];
for(size_t i = 0; i!= sizeOfArr; ++i)
walkthroughArray[i] = copy.walkthroughArray[i];
walkthroughArray[sizeOfArr].lexeme = 127;
size_t i = 0,
numbersCount = 0;
while(walkthroughArray[i].lexeme!= 127){
if(walkthroughArray[i].lexeme == 'x' || walkthroughArray[i].lexeme == 'y' ||!walkthroughArray[i].lexeme)
++numbersCount;
++i;
}
numArray = new double[numbersCount + 1];
}
Expression::~Expression(void)
{
delete[] walkthroughArray;
delete[] numArray;
}
double Expression::calculate(){
return calculate(0,0);
}
double Expression::calculate(double x){
return calculate(x,0);
}
double Expression::calculate(double x, double y){
start = walkthroughArray;
while((*walkthroughArray).lexeme!= 127) {
switch ((*walkthroughArray).lexeme) {
case 0:
*++numArray = (*walkthroughArray).number;
break;
case '+':/*Существует мнение что комутативные операции
могут выполнятся на разных платформах в разном
порядке поэтому дикримент перенесен в левую часть равенства*/
*(numArray-- - 1) += *numArray;
break;
case '*':
*(numArray-- - 1) *= *numArray;
break;
case '-':
*(numArray-- - 1) -= *numArray;
break;
case '%':
*numArray *= -1;
break;
case '/':
*(numArray-- - 1) /= *numArray;
break;
case '^':case -121:
*(numArray-- - 1) = pow(*(numArray-1),*numArray);
break;
case 'x':
*++numArray = x;
break;
case 'y':
*++numArray = y;
break;
case -128:
*numArray = sin(*numArray);
break;
case -127:
*numArray = cos(*numArray);
break;
case -126:
*numArray = tan(*numArray);
break;
case -125:
*numArray = 1 / tan(*numArray);
break;
case -124:
*(numArray-- - 1) = log(*(numArray-1))/log(*numArray);
break;
case -123:
*numArray = log10(*numArray);
break;
case -122:
*numArray = log(*numArray);
break;
case -120:
*numArray = pow(*numArray,0.5);
break;
case -119:
*numArray *= *numArray;
break;
case -118:
*numArray *= *numArray>0?1:-1;
break;
case -117:
*numArray = asin(*numArray);
break;
case -116:
*numArray = acos(*numArray);
break;
case -115:
*numArray = atan(*numArray);
break;
case -114:
*numArray = atan(1 / *numArray);
break;
case -113:
*numArray = sinh(*numArray);
|
break;
case -112:
*numArray = cosh(*numArray);
break;
}
//std::cout << *numArray << '\n';
++walkthroughArray;
}
--numArray;
walkthroughArray = start;
return numArray[1];
}
Expression& Expression::rebild(const std::string& st) { return rebild(st.c_str()); }
Expression& Expression::rebild(const char* expression)
{
delete[] walkthroughArray;
delete[] numArray;
//Переписываем содежимое строки expression в sourseString
int len = strlen(expression);
char* sourseString = new char[len *3];//Выражение, как правило, не длинное а нам пригодится память вовремя разбора. к тому же она будет очищена сразу после создания объекта
for (int i = 0, j = 0; i < len; ++i)
sourseString[j++] = expression[i];
sourseString[len] = 0;
sintAdaptation(sourseString);//Делает строку регистронезависимой, удаляет пробелы/'\t'/'\n', приводит скобочки к однообразию
addCode(sourseString);//Заменяет ссылки на функции символами от -128 для удобства дальнейшего анализа
addMult(sourseString);//Добавляет * и 0 для реализации унарного минуса. Функции объеденены по историческим причинам.
sortPoland(setArray(sourseString));/*При вызове преобразует строку в массив sintElem и высылает его для
сортировки в польскую нотацию*/
short i = 0,
numbersCount = 0,
opCount = 1;
while (walkthroughArray[i].lexeme!= 127){
if (walkthroughArray[i].lexeme == 'x' || walkthroughArray[i].lexeme == 'y' ||!walkthroughArray[i].lexeme)
++numbersCount;//Посчитать максимально возможное количество чисел в стеке(тоесть все числа вобще)
else
opCount +=!isUnary(walkthroughArray[i].lexeme);
++i;
}
//qDebug() << opCount << '<' << numbersCount;
if (opCount > numbersCount)
{
//qDebug() << "fuck";
delete[] walkthroughArray;
delete[] numArray;
walkthroughArray = new sintElem[2];
walkthroughArray->number = walkthroughArray->lexeme = 0;
(walkthroughArray + 1)->lexeme = 127;
numArray = new double[1];
*numArray = 0.;
}
numArray = new double[numbersCount + 1];//1 лишний элемент нужен для оптимизации алгаритма вычисления
//std::cout << "объект создан.\n";
return *this;
}
|
short strlen(char* st){
/*Так как функция из библиотеки выдаёт ворнинг я её переписал*/
char* len = st;
while (*len) ++len;
return len - st;
}
void Expression::sintAdaptation (char* st){
int i = -1, j = 0;
while(st[++i])//Регистронезависимость и приведение скобочек к единообразию
if(st[i] >= 'A' && st[i] <= 'Z')
st[i] -= 'A' - 'a';
else if(st[i] == '{' || st[i] == '[')
st[i] = '(';
else if(st[i] == '}' || st[i] == ']')
st[i] = ')';
i = 0;
while(st[i - 1])//Убираю пробелы, символы табуляции и переноса строки
{
while(st[i] && (st[i] == ' ' || st[i] == '\n' || st[i] == '\t'))
++i;
st[j] = st[i];
++j;
++i;
}
i = j = 0;
while(st[i - 1])//Убираю унарные плюсы
{
while(st[i] && st[i] == '+' && (!i || st[i - 1]!= ')' &&!isNumber(st[i - 1])))
++i;
st[j] = st[i];
++j;
++i;
}
}
void Expression::addCode (char* st)
{
int j,i=0;
while(st[i+3])
{
if(st[i]=='s'&&st[i+1]=='i'&&st[i+2]=='n')
{
st[i]=-128;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='c'&&st[i+1]=='o'&&st[i+2]=='s')
{
st[i]=-127;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='t'&&st[i+1]=='g')
{
st[i]=-126;
j=i+1;
while(st[j])
st[j]=st[j+++1];
}
else if(st[i]=='c'&&st[i+1]=='t'&&st[i+2]=='g')
{
st[i]=-125;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='l'&&st[i+1]=='o'&&st[i+2]=='g')
{
st[i]=-124;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='l'&&st[i+1]=='g')
{
st[i]=-123;
j=i+1;
while(st[j])
st[j]=st[j+++1];
}
else if(st[i]=='l'&&st[i+1]=='n')
{
st[i]=-122;
j=i+1;
while(st[j])
st[j]=st[j+++1];
}
else if(st[i]=='p'&&st[i+1]=='o'&&st[i+2]=='w')
{
st[i]=-121;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='s'&&st[i+1]=='q'&&st[i+2]=='r'&&st[i+3]=='t')
{
st[i]=-120;
j=i+1;
while(st[j+2])
st[j]=st[j+++3];
}
else if(st[i]=='s'&&st[i+1]=='q'&&st[i+2]=='r')
{
st[i]=-119;
j=i+1;
while(st[j+1])
st[j]=st[j+++2];
}
else if(st[i]=='a'&&st[i+1]=='b'&&st[i+2]=='s')
{
st[i]=-118;
j=i+1;
while(st[j+1])
st[j] = st[j+++2];
}
else if(st[i+4] && st[i+5])
if(st[i]=='a'&&st[i+1]=='r'&&st[i+2]=='c'&&st[i+3]=='s'&&st[i+4]=='i'&&st[i+5]=='n'){
st[i]=-117;
j=i+1;
while(st[j+4])
st[j] = st[j++ + 5];
}
else if(st[i]=='a'&&st[i+1]=='r'&&st[i+2]=='c'&&st[i+3]=='c'&&st[i+4]=='o'&&st[i+5]=='s'){
st[i]=-116;
j=i+1;
while(st[j+4])
st[j] = st[j++ + 5];
}
else if(st[i]=='a'&&st[i+1]=='r'&&st[i+2]=='c'&&st[i+3]=='t'&&st[i+4]=='g'){
st[i]=-115;
j=i+1;
while(st[j+3])
st[j] = st[j++ + 4];
}
else if(st[i]=='a'&&st[i+1]=='r'&&st[i+2]=='c'&&st[i+3]=='c'&&st[i+4]=='t'&&st[i+5]=='g'){
st[i]=-114;
j=i+1;
while(st[j+4])
st[j] = st[j++ + 5];
}
else if(st[i]=='s'&&st[i+1]=='i'&&st[i+2]=='n'&&st[i+3]=='h')
{
st[i]=-113;
j=i+1;
while(st[j+2])
st[j]=st[j+++3];
}
else if(st[i]=='c'&&st[i+1]=='o'&&st[i+2]=='s'&&st[i+3]=='h')
{
st[i]=-112;
j=i+1;
while(st[j+2])
st[j]=st[j+++3];
}
i++;
}
}
char* Expression::addMult (char* st)
/*Добавляет в анализируемую строку *. Ввиду сложности условвие срабатывания расписано в несколько строк
Функция не предназначена для полного решения вопроса а только помогает упростить ввод данных*/
{
int strLen = strlen(st),//Хрнаит длину строки изменяемую функцией!
i = 0, //Глобальный бегунок
j; //Бегунок используемый при добавлении '*'!
while (st[i]){
if (
(
((st[i]>47&&st[i]<58)||(st[i-1]=='p'&&st[i]=='i')||st[i]=='e'||st[i]=='x'||st[i]=='y'||st[i]==')')
&&
(st[i+1]=='(' || st[i+1]<=-100 || st[i+1]=='e' || st[i+1]=='p'&&st[i+2]=='i' || st[i+1] =='x' || st[i+1] == 'y')
)/*Если справа число или переменная или) а слева (, x, pi, e или функция*/
||
(
((st[i-1]=='p'&&st[i]=='i')||st[i]=='e'||st[i]=='x'||st[i]=='y'||st[i]==')')
&&
(st[i+1]>='0' && st[i+1]<='9')
)
)//Если нужно добавить *. Хоть и здоровенный но выносить в функцию не стал. Решил что не круто.
{
++strLen;
j=strLen;
st[j]=0;
while(i+1!= j)
{
--j;
st[j+1] = st[j];
}
st[j]='*';
}
++i;
}
//qDebug() << "theroes added $" << st << "$";
return st;
}
double Expression::setPoint (double arg, short del)
{
while(del--)
arg /= 10;
return arg;
}
Expression::sintElem* Expression::setArray (char* st)
/*
Преобразует строку в массив элементов следующего вида:
Каждый элемент имеет переменную lexeme типа char хранящую все лексэмы,
если же встречается число то оно записывается в переменную number типа double.
ВНИМАНИЕ! Признаком конца такого массива является выполнение равенства lexeme == 127
Воспринимает упоминания pi и e как чисел что делает невозможной экоспоненциальную форму записи числа в классическом виде.
если необходимо записать число в экспоненциальной форме пользуйтесь функцией pow,
анализатор оптимизирован для исполненя этой функции и упрощает алгоритм если
необходимо возвести в целую степень!
В анализаторе не предусмотрены методы позволяющие использовать не десятиричную форму представления чисел.
*/
{
int i=0;//Бегунок символьного массива
//Обозначаем унарную операцию заменив '-' на '%'
if(*st == '-')
*st = '%';
while(st[i++])
if(st[i-1] == '(' && st[i]=='-' && st[i+1]!='(' || (st[i-1] == '*' || st[i-1] == '/' || st[i-1] == '+' || st[i-1] == '-' || st[i-1] == '^') && st[i] == '-')
st[i] = '%';
int elKol=0;//Хранит количество элементов после завершения первого корневого цикла while
//Подсчитываем количество элементов чтобы выделить память. Выделяем память.
i=0;
while(st[i]){
//if(st[i] == '%' && st[i+1] == 'p' && st[i+2] == 'i')
//--elKol;//Если это вобще унарный минус перед пи
while((st[i] >= '0' && st[i] <= '9' || st[i] == '.' || st[i] == '%') && (st[i+1] >= '0' && st[i+1] <= '9' || st[i+1] == '.' || st[i+1] == 'p' || st[i+1] == 'e'))
++i;//Если текущий и следующий символы - части числа
if(st[i] == 'p' && st[i+1] == 'i')
++i;//Чтобы пи за 2 элемента не считать и включить унарный минус.
++elKol;
++i;
}
sintElem* firstAnalysisArray = new sintElem [elKol + 1];//Плюс место под признак конца масива
//Цикл основного анализа
i=0;
int point = 0, //Хранит количество знаков в числе после запятой.
j = 0, //Бегунок нового масива
det = 1; //Коэффициент учёта унарного минуса
bool isFigure = false;//Признак указывающий на то что до этого было число
while(st[i])
{
if(st[i]>='0'&&st[i]<='9')
if(point)//Если это число после запятой
firstAnalysisArray[j].number += setPoint(st[i] - '0',point++);
else if(isFigure){//Если не первая цифра числа
firstAnalysisArray[j].number *= 10;
firstAnalysisArray[j].number += st[i] - '0';
}
else{//Если это первая цифра в числе
firstAnalysisArray[j].lexeme = 0;//Фикссируем что это число
firstAnalysisArray[j].number = st[i] - '0';
isFigure = true;
if(i && st[i-1] == '%')//Если унарная операция
det=-1;
}
else if(st[i]=='.')
{
point=1;
if(!isFigure)
{
isFigure = true;
firstAnalysisArray[j].lexeme = 0;//Фикссируем что это число
firstAnalysisArray[j].number = 0.;
if(i && st[i-1] == '%')//Если унарная операция
det=-1;
}
}
else if(st[i]=='e'){
if(i && st[i - 1] == '%')
det = -1;
firstAnalysisArray[j].lexeme = 0;
firstAnalysisArray[j++].number = 2.718281828459045235360287471352662497757 * det;
det = 1;
}
else if(st[i]=='p'&&st[i+1]=='i'){
if(i && st[i - 1] == '%')
det=-1;
firstAnalysisArray[j].lexeme = 0;
firstAnalysisArray[j++].number = 3.141592653589793238462643383279502884197 * det;
det=1;//Занулить данные если раньше было число(рудиментарная форма защиты от ошибок)
++i;//отработано сразу два символа
}
else if(isFigure){
firstAnalysisArray[j++].number *= det;
firstAnalysisArray[j++].lexeme = st[i];
det = 1;
point = isFigure = 0;
}
else if(st[i]!= '%' || st[i + 1]!= 'p' && st[i + 1]!= 'e' && (st[i + 1] < '0' || st[i + 1] > '9') && st[i]!= '.')
firstAnalysisArray[j++].lexeme = st[i];
++i;
}
if(isFigure)
firstAnalysisArray[j].number *= det;
delete[] st;
firstAnalysisArray[elKol].lexeme = 127;//Записываем признак конца масcива
return firstAnalysisArray;
}
void Expression::recursionPlus (Expression::sintElem* sourseArray, short &i, short &j){
/*В случае +- мы ищем следующий +- или конец масива.
Рекурсия нужна чтобы всё остальное было полностью независимо*/
while(sourseArray[i].lexeme!= '+' && sourseArray[i].lexeme!= '-' && sourseArray[i].lexeme!= 127){
if(!sourseArray[i].lexeme || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y')
walkthroughArray[j++] = sourseArray[i++];
else if(sourseArray[i].lexeme == '+' || sourseArray[i].lexeme == '-' || sourseArray[i].lexeme == '*' || sourseArray[i].lexeme == '/' || sourseArray[i].lexeme == '^' || sourseArray[i].lexeme < -100 || sourseArray[i].lexeme == '%'){
sintElem cnt = sourseArray[i];
switch(cnt.lexeme)
{
case'*':case'/':
recursionMult (sourseArray,++i,j);
break;
case'^':
recursionPow (sourseArray,++i,j);
break;
case'%':
recursionUnary(sourseArray,++i,j);
break;
default:
recursionMain (sourseArray,++(++i),j);
while(sourseArray[i].lexeme == ',')
recursionMain(sourseArray,++i,j);
++i;
}
walkthroughArray[j++] = cnt;
}
else if(sourseArray[i].lexeme == '('){
recursionMain(sourseArray,++i,j);
++i;
}
else if(sourseArray[i].lexeme == ')' || sourseArray[i].lexeme == ',')
return;
}
}
void Expression::recursionMult (Expression::sintElem* sourseArray, short &i, short &j){
//В случае /* мы ищем следующий /*-+ или конец масива
while(!sourseArray[i].lexeme || sourseArray[i].lexeme == '^' || sourseArray[i].lexeme == '%' || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y' || sourseArray[i].lexeme == '(' || sourseArray[i].lexeme < -100){
if(!sourseArray[i].lexeme || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y')
walkthroughArray[j++] = sourseArray[i++];
else if(sourseArray[i].lexeme == '^' || sourseArray[i].lexeme < -100 || sourseArray[i].lexeme == '%'){
sintElem cnt = sourseArray[i];
switch(cnt.lexeme)
{
case '^'://свич уже вырожден в 2 исхода потому заменяется на if
recursionPow (sourseArray,++i,j);
break;
case '%':
recursionUnary(sourseArray,++i,j);
break;
default:
recursionMain (sourseArray,++(++i),j);
while(sourseArray[i].lexeme == ',')
recursionMain(sourseArray,++i,j);
++i;
}
walkthroughArray[j++] = cnt;
}
else if(sourseArray[i].lexeme == '('){
recursionMain(sourseArray,++i,j);
++i;
}
else if(sourseArray[i].lexeme == ')' || sourseArray[i].lexeme == ',')
return;
}
}
void Expression::recursionPow (Expression::sintElem* sourseArray, short &i, short &j){
//В случае ^ нам только и нужно что выписать содержимое идущих далее скобок или одно число
if(!sourseArray[i].lexeme || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y')
walkthroughArray[j++] = sourseArray[i++];
else if(sourseArray[i].lexeme < -100 || sourseArray[i].lexeme == '%'){//Это может быть только функция
sintElem cnt = sourseArray[i];
if(sourseArray[i].lexeme == '%'){
recursionUnary(sourseArray,++i,j);
}
else
{
recursionMain (sourseArray,++(++i),j);
while(sourseArray[i].lexeme == ',')
recursionMain(sourseArray,++i,j);
++i;//В конце стоит скобочка которую мы пропустили ++(++i) вызывая функцию
}
walkthroughArray[j++] = cnt;
}
else if(sourseArray[i].lexeme == '('){
recursionMain(sourseArray,++i,j);
++i;
}
}
void Expression::recursionUnary(Expression::sintElem* sourseArray, short &i, short &j){
//В случае % нам только и нужно что выписать содержимое идущих далее скобок или одно число
if(!sourseArray[i].lexeme || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y')
walkthroughArray[j++] = sourseArray[i++];
else if(sourseArray[i].lexeme < -100){//Это может быть только функция
sintElem cnt = sourseArray[i];
recursionMain(sourseArray,++(++i),j);
while(sourseArray[i].lexeme == ',')
recursionMain(sourseArray,++i,j);
++i;//В конце стоит скобочка которую мы пропустили ++(++i) вызывая функцию
walkthroughArray[j++] = cnt;
}
else if(sourseArray[i].lexeme == '('){
recursionMain(sourseArray,++i,j);
++i;
}
}
void Expression::recursionMain (Expression::sintElem* sourseArray,short&i,short&j){
while(sourseArray[i].lexeme!= 127){
if(!sourseArray[i].lexeme || sourseArray[i].lexeme == 'x' || sourseArray[i].lexeme == 'y')
walkthroughArray[j++] = sourseArray[i++];
else if(sourseArray[i].lexeme == '+' || sourseArray[i].lexeme == '-' || sourseArray[i].lexeme == '*' || sourseArray[i].lexeme == '/' || sourseArray[i].lexeme == '^' || sourseArray[i].lexeme < -100 || sourseArray[i].lexeme == '%'){
sintElem cnt = sourseArray[i];
switch(cnt.lexeme)
{//Для +-/*^ приходится писать рекурсивную функцию другого вида с другими условиями выхода
case'+':case'-':
recursionPlus(sourseArray,++i,j);
break;
case'*':case'/':
recursionMult(sourseArray,++i,j);
break;
case'^':
recursionPow (sourseArray,++i,j);
break;
case'%':
recursionUnary (sourseArray,++i,j);
break;
default://Если это не операции +-/*^ значит это функция и за её кодом идут скобки -> ++(++i)
recursionMain(sourseArray,++(++i),j);
while(sourseArray[i].lexeme == ',')
recursionMain(sourseArray,++i,j);
++i;//В конце стоит скобочка которую мы пропустили ++(++i) вызывая функцию
}
walkthroughArray[j++] = cnt;
}
else if(sourseArray[i].lexeme == '('){
recursionMain(sourseArray,++i,j);
++i;
}
else if(sourseArray[i].lexeme == ')' || sourseArray[i].lexeme == ',')
return;
}
}
void Expression::sortPoland (sintElem* sourseArray)
{
short int elemQuantity = 0,//Колличество элементов в новом масиве
i = 0, //Бегунок старого масива
j = 0; //Бегунок нового масива
while(sourseArray[i].lexeme!= 127)
if(sourseArray[i++].lexeme!= '(' && sourseArray[i-1].lexeme!= ')' && sourseArray[i-1].lexeme!= ',')
++elemQuantity;
walkthroughArray = new sintElem [elemQuantity + 1];
i = 0;
recursionMain(sourseArray, i, j);//i и j педедаются по ссылке(!)
walkthroughArray[j].lexeme = 127;
}
bool Expression::isExp(const std::string& str)
{
return isExp(str.c_str());
}
bool Expression::isNumber(char s) { return s >= '0' && s <= '9' || s == 'x' || s == 'y'; }
bool Expression::isLetter(char s) { return s >= 'a' && s <= 'z'; }
bool Expression::isExp(const char* St)
{
int i = -1, j = 0;
char* st = new char [strlen(St) * 2];
while(St[++i])//Проверка на наличие посторонних символов
if(St[i]!= ' ' && St[i]!= '\n')
if(St[i] >= 'A' && St[i] <= 'Z')
st[j++] = St[i] - ('A' - 'a');
else if(isLetter(St[i]) || isNumber(St[i]) ||
St[i] == '*' || St[i] == '/' || St[i] == '+' || St[i] == '-' ||
St[i] == '^' || St[i] == '(' || St[i] == ')' || St[i] == ',' || St[i] == '.')
st[j++] = St[i];
else if(St[i] == '}' || St[i] == ']')
st[j++] = ')';
else if(St[i] == '{' || St[i] == '[')
st[j++] = '(';
else
{
delete[] st;
return!true &&!false;
}
i = -1;
while(st[++i])
if(st[i] == 'p' && st[i + 1] == 'i')//Если это pi, заменить его на 77, чтобы в дальнейшем анализировать как число
{
st[i] = '7';
st[++i] = '7';
}
else if(st[i] == 'e' || st[i] == 'x' || st[i] =='y')//если это e, y или x
st[i] = '2';
st[j] = i = 0;
//std::cout << "Symbols is right.\nFree string is \"" << st << "\"\n";
if(*st!= 0 && (*st!= '+' && *st!= '-' && *st!= '(' &&!isNumber(*st) &&!isLetter(*st)))//Проверка на порядок следования
{
delete[] st;
return!true &&!false;
}
while(st[++i])
if((st[i] == '+' || st[i] == '-' || st[i] == '/' || st[i] == '*' || st[i] == '^' || st[i] == '(' || st[i] == ',') &&
!isNumber(st[i + 1]) &&!isLetter(st[i + 1]) && st[i + 1]!= '(' && st[i + 1]!= '-' && st[i + 1]!= '+'
|| st[i] == ')' &&
!isNumber(st[i + 1]) &&!isLetter(st[i + 1]) && st[i + 1]!= '(' && st[i + 1]!= '-' && st[i + 1]!= '+' && st[i + 1]!= '^'
&& st[i + 1]!= ')' && st[i + 1]!= '*' && st[i + 1]!= '/' && st[i + 1]!= ',' && st[i + 1]
|| isLetter(st[i]) &&
(!st[i + 1] ||!isLetter(st[i + 1]) && st[i + 1]!= '('))
{
delete[] st;
return!true &&!false;
}
//Тест последнего символа
--i;
if(st[i]!= ')' && (st[i] < '0' || st[i] > '9'))
{
delete[] st;
return!true &&!false;
}
//std::cout << "Sequence is right.\n";
//qDebug() << "()...";
i = -1;
j = 0;
while(st[++i])//Проверка на скобочки
{
if(st[i] == '(')
++j;
else if(st[i] == ')')
--j;
if(j < 0)
{
delete[] st;
return!true &&!false;
}
}
if(j)
{
delete[] st;
return!true &&!false;
}
//std::cout << "Brackets is right.\n";
//qDebug() << "funk...";
addCode(st);
i = -1;
while(st[++i])
{
if(isLetter(st[i]))//Если есть неопознанные функции - символы не заменённые на экваваленты
{
//std::cout << st << std::endl;
delete[] st;
return!true &&!false;
}
}
delete[] st;
return true;
}
char* Expression::argTest(char* st)
{
int j =!isUnary(*st);
++(++st);
int lBr = 1, rBr = 0;
while (*st && lBr!= rBr)
{
j -= *st == ',';
lBr += *st == '(';
rBr += *st == ')';
if (*st < -100)
{
st = argTest(st);
if (!st)
{
return 0;
}
}
++st;
}
if (lBr!= rBr || j)
{
return 0;
}
return ++st;
}
bool Expression::isUnary(char s) { return s == '%' || s < -100 && s!= -124 && s!= -121; }
bool Expression::isOperation(char s) { return s && s!= 'x' && s!= 'y'; }
Expression::sintElem Expression::doIt(char op, sintElem a)
{
//std::cout << op << a.number << std::endl;
sintElem ret;
ret.lexeme = 0;
switch (op)
{
case '%':
ret.number = 0 - a.number;
break;
case -128:
ret.number = sin(a.number);
break;
case -127:
ret.number = cos(a.number);
break;
case -126:
ret.number = tan(a.number);
break;
case -125:
ret.number = 1 / tan(a.number);
break;
case -123:
ret.number = log10(a.number);
break;
case -122:
ret.number = log(a.number);
break;
case -120:
ret.number = pow(a.number,0.5);
break;
case -119:
ret.number = a.number * a.number;
break;
case -118:
ret.number = *numArray>0? a.number: 0 - a.number;
break;
case -117:
ret.number = asin(a.number);
break;
case -116:
ret.number = acos(a.number);
break;
case -115:
ret.number = atan(a.number);
break;
case -114:
ret.number = atan(1 / a.number);
break;
case -113:
ret.number = sinh(a.number);
break;
case -112:
ret.number = cosh(a.number);
break;
}
return ret;
}
Expression::sintElem Expression::doIt(char op, sintElem a, sintElem b)
{
//std::cout << a.number << op << b.number << std::endl;
sintElem ret;
ret.lexeme = 0;
switch (op)
{
case '+':
ret.number = a.number + b.number;
break;
case '*':
ret.number = a.number * b.number;
break;
case '-':
ret.number = a.number - b.number;
break;
case '/':
ret.number = a.number / b.number;
break;
case '^':case -121:
ret.number = pow(a.number, b.number);
break;
case -124:
ret.number = log(a.number)/log(b.number);
break;
}
return ret;
}
unsigned Expression::operatorCount(sintElem* op)
{
unsigned k = 1;
signed j = 0;
while(k)//проверку на достижение начала массива ставить не нужно, если мы предпологаем нотацию разрешаемой
k += isOperation(op[-++j].lexeme)?!isUnary(op[-j].lexeme): -1;//по моему это приведёс нас ко второму операнду
return j;
}
void Expression::delElements(sintElem* from, unsigned how)
{
for(unsigned i = 0; from[i + how - 1].lexeme!= 127; ++i)
from[i] = from[i + how];
}
Expression& Expression::optimization()
{
unsigned counter = 0;
while(walkthroughArray[counter].lexeme!= 127)
++counter;
sintElem* temp = new sintElem[counter + 1];
unsigned i = 0, j = 0;
while(walkthroughArray[i].lexeme!= 127)
{
if(!walkthroughArray[i].lexeme || walkthroughArray[i].lexeme == 'x' || walkthroughArray[i].lexeme == 'y')
temp[j++] = walkthroughArray[i];
else
if(isUnary(walkthroughArray[i].lexeme))
if(!temp[j - 1].lexeme)
temp[j - 1] = doIt(walkthroughArray[i].lexeme, temp[j - 1]);
else
temp[j++] = walkthroughArray[i];
else
if(!temp[j - 1].lexeme &&!temp[j - 2].lexeme)
temp[j - 1] = doIt(walkthroughArray[i].lexeme, temp[j - 1], temp[--j]);
else
temp[j++] = walkthroughArray[i];
++i;
}
temp[j].lexeme = 127;
i = j = 0;
if(temp[1].lexeme!= 127)
++(++i);//речь о бинарных операциях, нет смысла изучать что там раньше третьего знака.
while(temp[i].lexeme!= 127)
{
switch(temp[i].lexeme)
{
case '*':
if(!temp[i - 1].lexeme && temp[i - 1].number == 1)//правый операнд мы можем проверить сразу
{
delElements(temp + i - 1, 2);//убираем 1 и *
--(--i);
}
else if(!temp[i - 1].lexeme && temp[i - 1].number == 0)
{
temp[i].lexeme = 0;
temp[i].number = 0;//Чтобы не вызывать два удаления записываем 0 вместо *
j = operatorCount(temp + i - 1);//собираем второй операнд, удаляем его и *.
delElements(temp + i - j - 1, j + 1);
i -= j + 1;
}
else//иначе просто собираем всё что попадает в правый операнд
{
j = operatorCount(temp + i);
if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 1)
{//удаляем 1 и само умножение.
delElements(temp + i, 1);
delElements(temp + i - j - 1, 1);
--(--i);
}
else if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0)
{
delElements(temp + i - j, j + 1);//удаляем всё кроме нуля
i -= j + 1;
}
}
break;
case '+': case '-':
if(!temp[i - 1].lexeme && temp[i - 1].number == 0)
{
delElements(temp + i - 1, 2);
--(--i);
}
else
{
j = operatorCount(temp + i);
if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0)
{
delElements(temp + i, 1);
delElements(temp + i - j - 1, 1);
--(--i);
}
}
break;
case '/':
if(!temp[i - 1].lexeme && temp[i - 1].number == 1)
{
delElements(temp + i - 1, 2);
--(--i);
}
if(!temp[i - 1].lexeme && temp[i - 1].number == 0)
{
temp[i].lexeme = 0;
temp[i].number = 1;
j = operatorCount(temp + i - 1);
delElements(temp + i - j - 1, j + 1);
i -= j + 1;
}
else
{
j = operatorCount(temp + i);
if(!temp[i - j - 1].lexeme && temp[i - j - 1].number == 0)
{
delElements(temp + i - j, j + 1);
i -= j + 1;
}
}
break;
case '^': case -121:
if(!temp[i - 1].lexeme && temp[i - 1].number == 1)
{
delElements(temp + i - 1, 2);
--(--i);
}
else
{
j = operatorCount(temp + i);
if(!temp[i - j - 1].lexeme && (temp[i - j - 1].number == 0 || temp[i - j - 1].number == 1))
{
delElements(temp + i - j, j + 1);
i -= j + 1;
}
}
break;
}
++i;
}
delete[] walkthroughArray;
walkthroughArray = temp;
/*
std::cout << "Оптимизированная нотация:\n";
for(i = 0; walkthroughArray[i].lexeme!= 127; ++i)
if(walkthroughArray[i].lexeme)
std::cout << walkthroughArray[i].lexeme << std::endl;
else
std::cout << walkthroughArray[i].number << std::endl;
//*/
return *this;
}
Приложение Б. Листинг
Листинг Б.1 - Файл zed.cpp, запускающий программу
Form1.h
#pragma once
#include <math.h>
#include "Form2.h"
#include "stdafx.h"
namespace zed {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace ZedGraph;
public ref class Form1: public System::Windows::Forms::Form
{
// Функция преобразования строки типа String в тип char, так как класс разбора работает только с Сhar
public:
char* SystemStringToChar(System::String^ string)
{
//возвращает значение ввиде Сhar
return (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(string);
}
// Функция преобразования компонента ZedGraph к необходимому виду
public:
void Load_Graw (void)
{
// Получим панель для рисования
ZedGraph::GraphPane ^myPane = zedGraphControl1->GraphPane;
// Очистим список кривых на тот случай, если до этого сигналы уже были нарисованы
myPane->CurveList->Clear();
myPane->GraphObjList->Clear();
//Запрет на самосогласования и выход за установленные границы
myPane->XAxis->Scale->MaxGrace=0;
myPane->XAxis->Scale->MinGrace=0;
myPane->YAxis->Scale->MaxGrace=0;
myPane->YAxis->Scale->MinGrace=0;
// Установим размеры шрифтов для подписей по осям
myPane->XAxis->Title->FontSpec->Size = 14;
myPane->YAxis->Title->FontSpec->Size = 14;
// Установим размеры шрифта для легенды
myPane->Legend->FontSpec->Size = 12;
// Установим размеры шрифта для общего заголовка
myPane->Title->FontSpec->Size = 13;
myPane->Title->FontSpec->FontColor=System::Drawing::Color::Black;
myPane->Title->Text = "Область постороения графиков";
myPane->XAxis->Title->Text = "x";
myPane->YAxis->Title->Text = "y";
//Установка фона панели графиков (не рабочая часть)
myPane->Fill->Color=System::Drawing::Color::LightGray;
//Установка фона панели отображения графиков
myPane->Chart->Fill = gcnew Fill(Color::White, Color::White, 0);
//Установка границы вывода графиков
myPane->Chart->Border->Color=System::Drawing::Color::Black;
// Устанавливаем интересующий нас интервал по оси X
myPane->XAxis->Scale->Min = -10;
myPane->XAxis->Scale->Max = 10;
//Ручная установка шага оси Х
myPane->XAxis->Scale->MinorStep = 1;
myPane->XAxis->Scale->MajorStep = 1;
// Устанавливаем интересующий нас интервал по оси Y
myPane->YAxis->Scale->Min = -10;
myPane->YAxis->Scale->Max = 10;
//Ручная установка шага оси Y
myPane->YAxis->Scale->MinorStep = 1;
myPane->YAxis->Scale->MajorStep = 1;
//Устанавливаем метки только возле осей!
myPane->XAxis->MajorTic->IsOpposite = false;
myPane->XAxis->MinorTic->IsOpposite = false;
myPane->YAxis->MajorTic->IsOpposite = false;
myPane->YAxis->MinorTic->IsOpposite = false;
//Рисуем сетку по X
myPane->XAxis->MajorGrid->IsVisible=false;
myPane->XAxis->MajorGrid->DashOn=5;
myPane->XAxis->MajorGrid->DashOff=5;
myPane->XAxis->MajorGrid->Color=System::Drawing::Color::Gray;
myPane->XAxis->Color=System::Drawing::Color::Gray;
//Рисуем сетку по Y
myPane->YAxis->MajorGrid->IsVisible=false;
myPane->YAxis->MajorGrid->DashOn=5;
myPane->YAxis->MajorGrid->DashOff=5;
myPane->YAxis->MajorGrid->Color=System::Drawing::Color::Gray;
myPane->YAxis->Color=System::Drawing::Color::Gray;
//******************************************************************************
// Добавляем информацию по регистрам вывода точек
//******************************************************************************
RollingPointPairList ^list1= gcnew RollingPointPairList (10000);
RollingPointPairList ^list2= gcnew RollingPointPairList (10000);
RollingPointPairList ^list3= gcnew RollingPointPairList (10000);
// Выводим пустые линии графиков на экран
LineItem ^F1Curve = myPane->AddCurve("Функция f(x)", list1, Color::Blue, SymbolType::None);
LineItem ^F2Curve = myPane->AddCurve("Функция g(x)", list2, Color::Red, SymbolType::None);
LineItem ^F3Curve = myPane->AddCurve("Функция h(x)", list3, Color::Green, SymbolType::None);
// Ширина линии
F1Curve->Line->Width=2;
F2Curve->Line->Width=2;
F3Curve->Line->Width=2;
// Задаем что линии гладкии
F1Curve->Line->IsSmooth=true;
F2Curve->Line->IsSmooth=true;
F3Curve->Line->IsSmooth=true;
// Обновлем данные об осях
zedGraphControl1->AxisChange ();
// Обновляем график
zedGraphControl1->Invalidate();
}
// Функция построения графиков
public:
void Graw_Draw (void)
{
// Объявляем переменные, которые указывают диапазон значений X
double min_x = System::Convert::ToDouble(textBox_x1->Text);
double max_x = System::Convert::ToDouble(textBox_x2->Text);
// Построение первого графика
if(textBox11->Text!= "")
{
// Преобразование строки типа String к типу Сhar
char *stroka1 = SystemStringToChar(textBox11->Text);
// Получаем линии от графиков
LineItem ^F1Curve=(LineItem ^)zedGraphControl1->GraphPane->CurveList[0];
IPointListEdit ^list1= (IPointListEdit ^) F1Curve->Points;
if(Expression::isExp(stroka1) == true)
{
// Вызов функции, которая разбирает строку типа Сhar, преобразуя ее в математическое выражение
Expression exp(stroka1);
for (double x =min_x; x <= max_x; x = x+0.01)
list1->Add(((double)(x)), exp.calculate(x));
}
else
MessageBox::Show("Не верный ввод даных","Ошибка",MessageBoxButtons::OK);
}
// Построение второго графика
if(textBox22->Text!= "")
{
// Преобразование строки типа String к типу Сhar
char *stroka2 = SystemStringToChar(textBox22->Text);
// Получаем линии от графиков
LineItem ^F2Curve=(LineItem ^)zedGraphControl1->GraphPane->CurveList[1];
IPointListEdit ^list2= (IPointListEdit ^) F2Curve->Points;
if(Expression::isExp(stroka2) == true)
{
// Вызов функции, которая разбирает строку типа Сhar, преобразуя ее в математическое выражение
Expression exp(stroka2);
for (double x =min_x; x <= max_x; x = x+0.01)
list2->Add(((double)(x)), exp.calculate(x));
}
else
MessageBox::Show("Не верный ввод даных","Ошибка",MessageBoxButtons::OK);
}
// Построение третьего графика
if(textBox33->Text!= "")
{
// Преобразование строки типа String к типу Сhar
char *stroka3 = SystemStringToChar(textBox33->Text);
// Получаем линии от графиков
LineItem ^F3Curve=(LineItem ^)zedGraphControl1->GraphPane->CurveList[2];
IPointListEdit ^list3= (IPointListEdit ^) F3Curve->Points;
if(Expression::isExp(stroka3) == true)
{
// Вызов функции, которая разбирает строку типа Сhar, преобразуя ее в математическое выражение
Expression exp(stroka3);
for (double x =min_x; x <= max_x; x = x+0.01)
list3->Add(((double)(x)), exp.calculate(x));
}
else
MessageBox::Show("Не верный ввод даных","Ошибка",MessageBoxButtons::OK);
}
// Обновлем данные об осях
zedGraphControl1->AxisChange ();
// Обновляем график
zedGraphControl1->Invalidate();
}
// Объявляем глобальные переменные, чтобы они запоминали значения в textBox_x1 и textBox_x2
double temp_x1, temp_x2;
public:
Form1(void)
{
InitializeComponent();
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
private: ZedGraph::ZedGraphControl^ zedGraphControl1;
private: System::Windows::Forms::Button^ button1;
private: System::Windows::Forms::Button^ button_master;
private: System::Windows::Forms::Button^ button_End;
private: System::Windows::Forms::TextBox^ textBox11;
private: System::Windows::Forms::Label^ label1;
private: System::Windows::Forms::Button^ button2;
private: System::Windows::Forms::Button^ button_save;
private: System::Windows::Forms::TextBox^ textBox_x2;
private: System::Windows::Forms::Label^ label3;
private: System::Windows::Forms::TextBox^ textBox_x1;
private: System::Windows::Forms::Label^ label2;
private: System::Windows::Forms::CheckBox^ checkBox1;
private: System::Windows::Forms::Label^ label4;
private: System::Windows::Forms::TextBox^ textBox22;
private: System::Windows::Forms::Label^ label5;
private: System::Windows::Forms::TextBox^ textBox33;
private: System::Windows::Forms::ToolTip^ toolTip1;
private: System::ComponentModel::IContainer^ components;
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
this->components = (gcnew System::ComponentModel::Container());
this->button1 = (gcnew System::Windows::Forms::Button());
this->zedGraphControl1 = (gcnew ZedGraph::ZedGraphControl());
this->button_master = (gcnew System::Windows::Forms::Button());
this->button_End = (gcnew System::Windows::Forms::Button());
this->textBox11 = (gcnew System::Windows::Forms::TextBox());
this->label1 = (gcnew System::Windows::Forms::Label());
this->button2 = (gcnew System::Windows::Forms::Button());
this->button_save = (gcnew System::Windows::Forms::Button());
this->textBox_x2 = (gcnew System::Windows::Forms::TextBox());
this->label3 = (gcnew System::Windows::Forms::Label());
this->textBox_x1 = (gcnew System::Windows::Forms::TextBox());
this->label2 = (gcnew System::Windows::Forms::Label());
this->checkBox1 = (gcnew System::Windows::Forms::CheckBox());
this->label4 = (gcnew System::Windows::Forms::Label());
this->textBox22 = (gcnew System::Windows::Forms::TextBox());
this->label5 = (gcnew System::Windows::Forms::Label());
this->textBox33 = (gcnew System::Windows::Forms::TextBox());
this->toolTip1 = (gcnew System::Windows::Forms::ToolTip(this->components));
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(12, 129);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(118, 53);
this->button1->TabIndex = 0;
this->button1->Text = L"Построить график";
this->toolTip1->SetToolTip(this->button1, L"Построение графиков");
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
//
// zedGraphControl1
//
this->zedGraphControl1->Location = System::Drawing::Point(162, 128);
this->zedGraphControl1->Name = L"zedGraphControl1";
this->zedGraphControl1->ScrollGrace = 0;
this->zedGraphControl1->ScrollMaxX = 0;
this->zedGraphControl1->ScrollMaxY = 0;
this->zedGraphControl1->ScrollMaxY2 = 0;
this->zedGraphControl1->ScrollMinX = 0;
this->zedGraphControl1->ScrollMinY = 0;
this->zedGraphControl1->ScrollMinY2 = 0;
this->zedGraphControl1->Size = System::Drawing::Size(698, 503);
this->zedGraphControl1->TabIndex = 1;
//
// button_master
//
this->button_master->Location = System::Drawing::Point(770, 13);
this->button_master->Name = L"button_master";
this->button_master->Size = System::Drawing::Size(90, 91);
this->button_master->TabIndex = 2;
this->button_master->Text = L"Мастер функций";
this->toolTip1->SetToolTip(this->button_master, L"Мастер функций");
this->button_master->UseVisualStyleBackColor = true;
this->button_master->Click += gcnew System::EventHandler(this, &Form1::button_master_Click);
//
// button_End
//
this->button_End->Location = System::Drawing::Point(12, 467);
this->button_End->Name = L"button_End";
this->button_End->Size = System::Drawing::Size(118, 53);
this->button_End->TabIndex = 3;
this->button_End->Text = L"Выход";
this->toolTip1->SetToolTip(this->button_End, L"Выход");
this->button_End->UseVisualStyleBackColor = true;
this->button_End->Click += gcnew System::EventHandler(this, &Form1::button_End_Click);
//
// textBox11
//
this->textBox11->Location = System::Drawing::Point(208, 12);
this->textBox11->Name = L"textBox11";
this->textBox11->Size = System::Drawing::Size(556, 20);
this->textBox11->TabIndex = 4;
this->toolTip1->SetToolTip(this->textBox11, L"выражение f(x)");
//
// label1
//
this->label1->AutoSize = true;
this->label1->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 12, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(204)));
this->label1->Location = System::Drawing::Point(162, 12);
this->label1->Name = L"label1";
this->label1->Size = System::Drawing::Size(40, 20);
this->label1->TabIndex = 5;
this->label1->Text = L"f(x)=";
//
// button2
//
this->button2->Location = System::Drawing::Point(12, 236);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(118, 53);
this->button2->TabIndex = 6;
this->button2->Text = L"Очистить";
this->toolTip1->SetToolTip(this->button2, L"Очистить область построения графиков");
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
//
// button_save
//
this->button_save->Location = System::Drawing::Point(12, 349);
this->button_save->Name = L"button_save";
this->button_save->Size = System::Drawing::Size(118, 53);
this->button_save->TabIndex = 7;
this->button_save->Text = L"Сохранить график";
this->toolTip1->SetToolTip(this->button_save, L"Сохранение графиков в файл");
this->button_save->UseVisualStyleBackColor = true;
this->button_save->Click += gcnew System::EventHandler(this, &Form1::button_save_Click);
//
// textBox_x2
//
this->textBox_x2->Location = System::Drawing::Point(113, 578);
this->textBox_x2->Name = L"textBox_x2";
this->textBox_x2->Size = System::Drawing::Size(25, 20);
this->textBox_x2->TabIndex = 15;
this->textBox_x2->Text = L"10";
this->toolTip1->SetToolTip(this->textBox_x2, L"Диапазон значений X");
this->textBox_x2->TextChanged += gcnew System::EventHandler(this, &Form1::textBox_x2_TextChanged);
//
// label3
//
this->label3->AutoSize = true;
this->label3->Location = System::Drawing::Point(88, 581);
this->label3->Name = L"label3";
this->label3->Size = System::Drawing::Size(19, 13);
this->label3->TabIndex = 14;
this->label3->Text = L"до";
//
// textBox_x1
//