Last active
January 13, 2023 11:56
-
-
Save MisterTimur/86b2810a6d9942d8d869967b978ae727 to your computer and use it in GitHub Desktop.
Интерпретатор на C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ConsoleApplication39.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы. | |
// Абдулов Тимур | |
#include "pch.h" | |
#include <iostream> | |
#include <string> | |
const char TI_SLO=1;// тип Слово | |
const char TI_CIF=2;// тип Число | |
const char TI_ZNA=3;// тип Занк | |
using namespace std; | |
typedef string STR; | |
typedef char CHA; | |
typedef bool BOL; | |
#pragma region ======================== Tr_Is_Float | |
// ゆうきイセル | |
// Функция определяет являеться ли строка числом | |
bool Tr_Is_Float(STR iStr){ | |
bool p=0; // Количество точек | |
bool r=1; // Результат проверки по умолчанию true | |
int i=0; // Для цикла перебора символов | |
if(iStr[i]=='-') i++; // если минус то прпускаем | |
if(iStr[i]=='.') {i++;p++;} // если точка то пропускаем | |
for(;iStr[i]!='\0';i++){ // Перебираем знаки в строке | |
if(iStr[i]=='.'){// Если встретилась точка смотрим сколько их | |
if (p) r=0;// Если точек больше true то есть 1 то нечисло | |
else p++;// Увеличиваем количество точек с false на true | |
continue;}// Продолжаем работу цикла тут можно потсавить else | |
if(iStr[i]<'0'||iStr[i]>'9')r=0;// Если это не число то результат равен false | |
}// ПОсле выхода из цикла i всегда больше 0 | |
if(iStr[i-1]<'0'||iStr[i-1]>'9')r=0;// Первый символ дожен быть числом | |
return r;// Вернуть результат прверки строки | |
} | |
#pragma endregion | |
#pragma region ====================== Tr_StrToFloat | |
float Tr_StrToFloat(STR iStr){ // Переводит строку в float с проверкой | |
float res=0;// В случае ошибки вернет 0 | |
if (Tr_Is_Float(iStr)) // ПРоерка если в строке число то | |
res=strtof(&iStr[0],NULL);// Перевести в Float | |
return res;// Возращает результат | |
} | |
float F(char* iStr){return Tr_StrToFloat(iStr);} | |
#pragma endregion | |
bool EtoBuk(char iCha) { // ОРпределяет буквали это ? | |
bool Rez=false; | |
if (iCha>='a' && iCha<='z') Rez=true; else | |
if (iCha>='A' && iCha<='Z') Rez=true; else | |
if (iCha=='_' ) Rez=true; | |
return Rez; | |
} | |
bool EtoCif(char iCha) { // ОРпределяет цифра ли это ? | |
bool Rez=false; | |
if (iCha>='0' && iCha<='9') Rez=true; | |
return Rez; | |
} | |
bool EtoCifBuk(char iCha) { // Если это Буква или цифра то true | |
return ( EtoBuk(iCha) || EtoCif(iCha) ); | |
} | |
string ReadSlovo(string &iStr,int &iPos,int &iLen) { // Читаем слово из строки | |
string Rez="";// Если не удалось прочитать слово вернет пустую строку | |
if (EtoBuk(iStr[iPos])) // Если это буква Слово может начинаться с буквы | |
while ((iPos<iLen) && (EtoCifBuk(iStr[iPos]))) // Содержит буквы или цифры | |
{ Rez=Rez+iStr[iPos]; iPos=iPos+1; } // Складываем слово и увеличиваем iPos | |
return Rez;// Возвращаем рузельтат | |
} | |
string ReadChisl(string &iStr,int &iPos,int &iLen) { // Читаем число из строки | |
string Rez=""; | |
if (EtoCif(iStr[iPos])) // Если это цифра | |
while ((iPos<iLen) && (EtoCif(iStr[iPos]))) | |
Rez += iStr[iPos++]; | |
return Rez; | |
} | |
string ReadZnak2(string &iStr,int &iPos,int &iLen) { // Читаем двоной знак | |
string Rez=""; | |
if (iPos<iLen+1) { | |
string S; | |
S=S+iStr[iPos]; | |
S=S+iStr[iPos+1]; | |
if ( | |
(S=="&&") || | |
(S=="||") || | |
(S==":=") || | |
(S=="==") || | |
(S=="!=") || | |
(S=="<>") || | |
(S==">=") || | |
(S=="<=") | |
) {Rez=S;iPos=iPos+2;} | |
} | |
return Rez; | |
} | |
string ReadZnak1(string &iStr,int &iPos,int &iLen) { // Читаем занк одинарный | |
string Rez=""; | |
if (iPos<iLen) { | |
string S; | |
S=S+iStr[iPos]; | |
if ( | |
(S=="&") || | |
(S=="|") || | |
(S=="{") || | |
(S=="}") || | |
(S=="(") || | |
(S==")") || | |
(S=="[") || | |
(S=="]") || | |
(S=="=") || | |
(S=="+") || | |
(S=="-") || | |
(S=="*") || | |
(S=="/") || | |
(S=="<") || | |
(S==">") | |
) {Rez=S;iPos=iPos+1;} | |
} | |
return Rez; | |
} | |
class TEl { | |
public: | |
STR TXT;// Тект Элемента | |
STR ZNA;// Сдержимое элемента занчение | |
BOL FUN;// Если это функция | |
CHA TIP;// Тип токена | |
TEl*ROD;// Ссылка на родительский элемент | |
TEl*PRE;// Предыдущие слово в списке | |
TEl*NEX;// Следующее слово в списке | |
TEl*FIR;// Первый элемент в вложеном списке | |
TEl*LAS;// Последний элемент в вложеном списке | |
TEl*ADD(TEl*iEl) {// Добавить элемент в список | |
TEl*Rez; | |
iEl->DEL();// ОТсоеденяем от предудущего списка | |
if (FIR==0) { // Если вложеных элементов нету | |
FIR=iEl; // указываю как перывй элемент вложеного списка | |
LAS=FIR;// Указываю что он же являеться последним | |
FIR->PRE=0;// Указываю что предыдущего элемента нету | |
FIR->NEX=0;// Указываю что следующего элемента нету | |
FIR->ROD=this;// Указываю родительский элемент | |
Rez=FIR; | |
} | |
else { // Если уже есть вложеные элементы то крепим к LST | |
LAS->NEX=iEl;// Доабвлю новый элемент в конец списка | |
LAS->NEX->PRE=LAS;// Указваем ссылку на предыдыщий элемент | |
LAS->NEX->ROD=this;// Указывем родительский элемент | |
LAS->NEX->NEX=0;// Указывем следующий элемент | |
LAS=LAS->NEX;// Указываем как новый послдений эдемент в списке | |
Rez=LAS; | |
} | |
return Rez; | |
} | |
TEl*DEL() { // Удаляет элемент из списка | |
if (ROD!=0) // Если удаляемый элемент являеться последним в списке | |
if (ROD->LAS==this) ROD->LAS=PRE; | |
if (ROD!=0) // Если удаляемый элемент являеться Первым в списке | |
if (ROD->FIR==this) ROD->FIR=NEX; | |
if (PRE!=0) PRE->NEX=NEX;// Отсоеденяем от предыдыщего | |
if (NEX!=0) NEX->PRE=PRE;// Отсоеденяем от следующего | |
NEX=0; | |
PRE=0; | |
ROD=0; | |
return this; | |
} | |
TEl*ADD(STR iStr,CHA iTip) {// Добавить слово в список | |
TEl*Rez=0; | |
if (iStr!="") { | |
Rez = new TEl();// Создаю новый элемент | |
Rez->TXT=iStr;// Указываю текс элемента | |
Rez->ZNA=iStr;// Указываю значение элемента | |
Rez->TIP=iTip;// Указываю тип эдемента | |
ADD(Rez);// Добавлю соданый элемент в вложенй список | |
} | |
return Rez;// Возвращаю ссылку на созданый эдемент | |
} | |
TEl*FIN(STR iStr) { // Ищим функцию с именем iStr | |
TEl*Rez=0 ;// Результат поиска фунции | |
if ((FUN) && (TXT==iStr)) Rez=this; | |
TEl*lEl=this;// Поиск начинаем с текущего элемента | |
lEl=lEl->PRE;// Переходим к предыдущему элементу | |
while ((lEl!=0)&&(Rez==0)) // Переббираем элементы | |
if ((lEl->FUN) && (lEl->TXT==iStr)) Rez=lEl;else | |
lEl=lEl->PRE;// Переходим к предыдущему элементу | |
// ПОиск переменной внутри параметров функции | |
if (Rez==0) | |
if (ROD!=0) | |
if (ROD->FUN) | |
if (ROD->FIR->TXT=="(") | |
if (ROD->FIR->FIR!=0) { | |
TEl*lEl=ROD->NEX->NEX; | |
while ((lEl!=0) && (Rez==0)) | |
if (lEl->TXT==iStr) Rez=lEl;else lEl=lEl->NEX; | |
} | |
if ((Rez==0) && (ROD!=0)) Rez=ROD->FIN(iStr); | |
return Rez; | |
} | |
TEl*COP(TEl*IRod,TEl*IPre){// Возвращает копию Элемента | |
TEl*Rez=new TEl(); | |
Rez->TXT=TXT; | |
Rez->ZNA=ZNA; | |
Rez->TIP=TIP; | |
Rez->FUN=FUN; | |
Rez->ROD=IRod; | |
Rez->PRE=IPre; | |
Rez->NEX=0; | |
Rez->FIR=0; | |
if (FIR!=0) { | |
Rez->FIR = FIR->COP(Rez,0); | |
TEl*Ne=FIR->NEX; | |
TEl*Pr=Rez->FIR; | |
while (Ne!=0) { | |
Pr->NEX=Ne->COP(Rez,Pr); | |
Ne=Ne->NEX; | |
Pr=Pr->NEX; | |
} | |
} | |
return Rez; | |
} | |
TEl() { // Конструктор на всякий пажарный случай | |
PRE=0; | |
NEX=0; | |
LAS=0; | |
FIR=0; | |
} | |
void CopPar(TEl*iEl1,TEl*iEl2) { // Копирование параметров функции | |
TEl*L1=iEl1; | |
TEl*L2=iEl2; | |
while ((L1!=0) && (L2!=0)) { | |
L1->ZNA=L2->ZNA; | |
L1=L1->NEX; | |
L2=L2->NEX; | |
}; | |
} | |
void OP_SCO() { // Операция Скобка | |
if (FIR!=0){ | |
Runs();// Вычислем содержимое скобки | |
ZNA=FIR->ZNA; | |
} | |
} | |
void OP_MUL() { // Операция умножения | |
if (FIR!=0) // ПРверяем есть ли первый элемент вложеного списка | |
if (FIR->NEX!=0) // ПРоверяем есть ли второй эдемент вложеного списка | |
{ | |
FIR->Run();// Выполнить первый элемент | |
FIR->NEX->Run();// Выполнить второй элемент | |
if (Tr_Is_Float(FIR->ZNA)) // Если это число | |
if (Tr_Is_Float(FIR->NEX->ZNA)) // Если это число | |
ZNA=to_string(Tr_StrToFloat(FIR->ZNA)*Tr_StrToFloat(FIR->NEX->ZNA)); | |
} | |
} | |
void OP_DIV() { // Операция деления | |
if (FIR!=0) // ПРверяем есть ли первый элемент вложеного списка | |
if (FIR->NEX!=0) // ПРоверяем есть ли второй эдемент вложеного списка | |
{ | |
FIR->Run();// Выполнить первый элемент | |
FIR->NEX->Run();// Выполнить второй элемент | |
if (Tr_Is_Float(FIR->ZNA)) // Если это число | |
if (Tr_Is_Float(FIR->NEX->ZNA)) // Если это число | |
if (Tr_StrToFloat(FIR->NEX->ZNA)!=0) // Если второе занчение не ноль | |
ZNA=to_string(Tr_StrToFloat(FIR->ZNA)/Tr_StrToFloat(FIR->NEX->ZNA)); | |
} | |
} | |
void OP_SUM() { // Операция сложения | |
if (FIR!=0) // ПРверяем есть ли первый элемент вложеного списка | |
if (FIR->NEX!=0) // ПРоверяем есть ли второй эдемент вложеного списка | |
{ | |
FIR->Run();// Выполнить первый элемент | |
FIR->NEX->Run();// Выполнить второй элемент | |
if ((Tr_Is_Float(FIR->ZNA)) && (Tr_Is_Float(FIR->NEX->ZNA))) | |
ZNA=to_string(Tr_StrToFloat(FIR->ZNA)+Tr_StrToFloat(FIR->NEX->ZNA)); | |
else | |
ZNA=FIR->ZNA+FIR->NEX->ZNA; | |
} | |
} | |
void OP_SUB() { // Операция вычитания | |
if (FIR!=0) // ПРверяем есть ли первый элемент вложеного списка | |
if (FIR->NEX!=0) // ПРоверяем есть ли второй эдемент вложеного списка | |
{ | |
FIR->Run();// Выполнить первый элемент | |
FIR->NEX->Run();// Выполнить второй элемент | |
if ((Tr_Is_Float(FIR->ZNA)) && (Tr_Is_Float(FIR->NEX->ZNA))) | |
ZNA=to_string(Tr_StrToFloat(FIR->ZNA)-Tr_StrToFloat(FIR->NEX->ZNA)); | |
} | |
} | |
void OP_LET() { // Операция присваивания | |
if ((FIR!=0)&&(FIR->NEX!=0)){ | |
TEl*FU=FIN(FIR->TXT); | |
if (FU!=0){ | |
FIR->NEX->Run(); | |
FU->ZNA=FIR->NEX->ZNA; | |
} | |
} | |
} | |
void OP_PRI() { // Операция вывода в консоль | |
if (FIR!=0) // Если есть вложеныей элемент | |
if (FIR->TXT=="(") // Если вложеный элемент это скобка | |
{ | |
FIR->Runs(); // Выполняю содержимое скобки | |
TEl*lEl=0; // ДЛя перебор элементов | |
if (FIR->FIR!=0) // Если в скобке есть что то | |
lEl=FIR->FIR; // Беру первый элемент в скобке | |
while (lEl!=0) { // Пока не дойду до кона списка | |
cout<<lEl->ZNA; // Вывожу в консоль | |
lEl=lEl->NEX; // Переходу к следующему элементу в скобке | |
} | |
} | |
} | |
void OP_FUN() { // Пытаемся выполнить как функцию | |
TEl*FN=FIN(TXT);// Ищим функцию )))) | |
if (FN!=0) {// Если такая функция найдена | |
TEl*RU=FN->COP(ROD,PRE);// Создаю копию функции | |
FIR->Run();// Вычисляю содержимое параметров если они есть | |
CopPar(FIR->FIR,RU->FIR->FIR);// Копирую параметры | |
RU->FIR->NEX->Run();// Запускаю функцию | |
ZNA=RU->ZNA;// Влзращаю результат | |
free(RU);// Освобождаю копию функции | |
} | |
} | |
void Run() { // Выполнить элемент | |
if (TXT=="(" ) OP_SCO();else // Операция Скобка | |
if (TXT=="*" ) OP_MUL();else // Операция умножения | |
if (TXT=="/" ) OP_DIV();else // Операция деления | |
if (TXT=="+" ) OP_SUM();else // Операция сложения | |
if (TXT=="-" ) OP_SUB();else // Операция вычитания | |
if (TXT==":=" ) OP_LET();else // Операция присваивания | |
if (TXT=="PRINT") OP_PRI();else // Операция Вывода в консоль | |
if (TXT=="{" ) Runs();else // Операция Скобка | |
if (TIP==TI_SLO ) OP_FUN(); // Пытаемся выполнить как функцию | |
} | |
void Runs() { // Выполнить элементы | |
TEl*lEl=FIR;// Перебираем элементы в списке | |
while (lEl!=0) { // Пока не дойдем до конца списка | |
if (!lEl->FUN) lEl->Run();// Выполнить элемент | |
lEl=lEl->NEX;// Передти к следующему | |
} | |
} | |
}; | |
TEl* RedSlo(STR iStr) { // Создает список слов | |
int lPos=0;// Номер читаемого символа в строке | |
int lLen=iStr.length();// Это просто длина строки | |
TEl*REZ = new TEl();// Структура программы здесь храниться программ | |
while (lPos<lLen) // Создаем список слов в PRO | |
if (!REZ->ADD(ReadSlovo(iStr,lPos,lLen),TI_SLO)) | |
if (!REZ->ADD(ReadChisl(iStr,lPos,lLen),TI_CIF)) | |
if (!REZ->ADD(ReadZnak2(iStr,lPos,lLen),TI_ZNA)) | |
if (!REZ->ADD(ReadZnak1(iStr,lPos,lLen),TI_ZNA)) lPos=lPos+1; | |
return REZ; | |
} | |
void Vlojit(TEl*iEl,char S1,char S2) { // Вложить скобки | |
TEl*lEl=iEl->FIR;// Перебираемые элементы текущий элемент | |
TEl*lSc=0 ;// Сюда складываем последующие элементы после скобки | |
TEl*MEl; | |
while (lEl!=0) {// ПОка не встретим конец списка | |
if (lEl->FIR!=0) Vlojit(lEl,S1,S2); | |
MEl=lEl->NEX; | |
if (lEl->TXT[0]==S1) { | |
if (lSc!=0) lSc=lSc->ADD(lEl);else lSc=lEl ; | |
} | |
else if (lEl->TXT[0]==S2) { | |
lEl->DEL();lSc=lSc->ROD;if (lSc==iEl)lSc=0; | |
}// Поднимаемся на уровент наверх | |
else if (lSc!=0 ) lSc->ADD(lEl); | |
lEl=MEl; | |
} | |
} | |
void Debugr(TEl*iEl,string iOt) { // Выводит содержимое эдемента в консоль | |
TEl*lEl=iEl; | |
while (lEl!=0){ | |
cout<<iOt<<lEl->TXT<<endl; | |
if (lEl->FIR!=0) Debugr(lEl->FIR,iOt+" "); | |
lEl=lEl->NEX; | |
} | |
} | |
void VlojPA(TEl*iEl) { // Вкладывает парметры нутрь функции | |
// Перебираемые элементы текущий элемент | |
TEl* lEl = iEl->FIR; | |
// Пока не встретим конец списка | |
while (lEl != 0) { | |
if (lEl->TIP==TI_SLO) | |
if ((lEl->NEX!=0)&&(lEl->NEX->TXT=="(")) | |
lEl->ADD(lEl->NEX);else lEl->ADD("(",TI_ZNA); | |
VlojPA(lEl); | |
lEl = lEl->NEX; | |
} | |
} | |
void VlojBL(TEl*iEl) { // Вкладывает парметры нутрь функции | |
// Перебираемые элементы текущий элемент | |
TEl* lEl = iEl->FIR; | |
// Пока не встретим конец списка | |
while (lEl != 0) { | |
if (lEl->TIP==TI_SLO) | |
if (lEl->NEX!=0) | |
if (lEl->NEX->TXT=="{") | |
{ | |
lEl->FUN=true;// Это функция | |
lEl->ADD(lEl->NEX); | |
} | |
VlojBL(lEl); | |
lEl = lEl->NEX; | |
} | |
} | |
void VlojZ1(TEl*iEl) { // Вкладывает знаки Умножение деление | |
// Перебираемые элементы текущий элемент | |
TEl* lEl = iEl->FIR; | |
// Пока не встретим конец списка | |
while (lEl != 0) { | |
if (lEl->NEX!=0) | |
if (lEl->PRE!=0) | |
if ((lEl->TXT=="*")||(lEl->TXT=="/")) { | |
lEl->ADD(lEl->PRE); // Пермещаю предыдущий элемент в ЗНАК */ | |
lEl->ADD(lEl->NEX); // Пермещаю следующий элемент в ЗНАК */ | |
} | |
if (lEl->FIR != 0) VlojZ1(lEl); | |
lEl = lEl->NEX; | |
} | |
} | |
void VlojZ2(TEl*iEl) { // Вкладывает знаки Умножение деление | |
// Перебираемые элементы текущий элемент | |
TEl* lEl = iEl->FIR; | |
// Пока не встретим конец списка | |
while (lEl != 0) { | |
if ((lEl->TXT=="+")||(lEl->TXT=="-")) | |
if (lEl->NEX!=0) | |
if (lEl->PRE!=0) | |
{ | |
lEl->ADD(lEl->PRE); // Пермещаю предыдущий элемент в ЗНАК +- | |
lEl->ADD(lEl->NEX); // Пермещаю следующий элемент в ЗНАК +- | |
} | |
if (lEl->FIR != 0) VlojZ2(lEl); | |
lEl = lEl->NEX; | |
} | |
} | |
void VlojZ3(TEl*iEl) { // Вкладывает знаки присвоения | |
// Перебираемые элементы текущий элемент | |
TEl* lEl = iEl->FIR; | |
// Пока не встретим конец списка | |
while (lEl != 0) { | |
if (lEl->TXT==":=") | |
if (lEl->NEX!=0) | |
if (lEl->PRE!=0) | |
{ | |
lEl->ADD(lEl->PRE); // Пермещаю предыдущий элемент в ЗНАК := | |
lEl->ADD(lEl->NEX); // Пермещаю следующий элемент в ЗНАК := | |
} | |
VlojZ3(lEl); | |
lEl = lEl->NEX; | |
} | |
} | |
int main(int argc, char** argv) { | |
STR prog=" A(){A:=1;} PRINT( (1+2)*A) ";// Текст программы | |
TEl*PRO=RedSlo(prog);// Разбиваем строку на слова | |
Vlojit(PRO,'[',']');// Вкладываем квадратные скобки | |
Vlojit(PRO,'(',')');// Вкладываем скобки | |
Vlojit(PRO,'{','}');// Вкладываем исполнительные блоки | |
VlojPA(PRO);// Вкладываем параметры функций | |
VlojBL(PRO);// Вкладываем исполнительне блоки | |
VlojZ1(PRO);// Вкладываем Умнеожения деления */ | |
VlojZ2(PRO);// Вкладываем Сложения вычитания +- | |
VlojZ3(PRO);// Вкладываем операции присвоения := | |
PRO->Runs();// Выполнить программу | |
Debugr(PRO," ");// Выводим содержимое элемента | |
cout << endl << endl; // ПРосто перевод строки | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Спасибо !