Void readFile(qString);
private:
struct lexemeDescription
{
QString text;
QString type;
int stringNumber;
};
lexemeDescription lexDesc;
LexFSM::stateName state;
QVector<lexemeDescription> lexemes;
QMap<QString, int> identifiers;
int identifiersCnt;
QFile file;
QTextStream in;
bool flagEOF;
QString readString();
QString line;
int stringNumber;
signals:
void sendLog(QString, QString);
void setNextChar(QChar);
void setRedLine(int);
void fileSuccessfullyOpened();
void endOfFile();
void showLexeme(QString, QString, QString num=0);
void sendLexemes(QVector<lexemeDescription>);
void sendIdentifiers(QMap<QString, int>);
private slots:
void setError();
void readChar();
void addLexeme(QString, QString, QString);
};
#endif //LEXANALYSER_H
LexAnalyser.cpp
#include "LexAnalyser.h"
#include "LexFSM.h"
#include <QMessageBox>
#include <QChar>
//Лексический анализатор
LexAnalyser::LexAnalyser(QObject* parent)
: QObject(parent)
{
stringNumber=0;
flagEOF=0;
identifiersCnt=0;
}
void LexAnalyser::readFile(QString fileName)
{
// file.close();
emit sendLog(tr("Открытие файла %1").arg(fileName), "MESSAGE");
flagEOF=0; //флаг конца файла
stringNumber=0;
file.setFileName(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) //открываем файл на чтение
QMessageBox::critical(0, "Error", "Can't open file for read", "OK");
in.setDevice(&file);
emit fileSuccessfullyOpened(); //сообщаем об открытии файла
}
//чтение очередной строки из файла
QString LexAnalyser::readString()
{
line=""; //обнуление строки
if (!in.atEnd()) //если не конец файла
{
stringNumber++; //номер строки
emit sendLog(tr("Чтение строки %1").arg(stringNumber), "MESSAGE");
line=in.readLine().simplified(); //чтение строки
}
else //конец файла
{
emit sendLog(tr("Чтение файла закончено"), "END");
file.close(); //закрытие файла
flagEOF=1; //флаг конца файла
}
return line;
}
//чтение очередного символа из строки
void LexAnalyser::readChar()
{
if (!line.isEmpty()) //если строка не пуста
{
QChar c=line[0];
line.remove(0, 1); //удаляем прочитанный символ в строке
emit setNextChar(c); //посылаем символ автомату
}
else //строка пуста
{
//читаем новую строку
line=readString();
if (flagEOF) //флаг конца файла
{
emit endOfFile(); //сообщить, что достигнут конец файла
emit setNextChar(QChar(65534)); //послать автомату символ, говорящий, что достигнут конец файла
emit sendLexemes(lexemes); //послать лексемы синтаксическому анализатору
sendLog(tr("Отправлены лексемы синтаксическому анализатору"), "MESSAGE");
emit sendIdentifiers(identifiers); //послать идентификаторы синтаксическому анализатору
sendLog(tr("Отправлены идентификаторы синтаксическому анализатору"), "MESSAGE");
}
else //не конец файла
emit setNextChar('\0'); //послать символ, говорящий, что достигнут конец текущей строки
}
}
//сообщить об ошибке
void LexAnalyser::setError()
{
QMessageBox::critical(0, "ERROR", tr("Лексическая ошибка в %1 строке").arg(stringNumber), "OK");
emit sendLog(tr("Лексическая ошибка в %1 строке").arg(stringNumber), "ERROR");
emit setRedLine(stringNumber);
emit sendLog(tr("Чтение файла закончено"), "END");
file.close(); //закрытие файла
in.readAll();
flagEOF=1; //флаг конца файла
}
//добавить лексему в таблицу идентификаторов
void LexAnalyser::addLexeme(QString text, QString stateString, QString type)
{
if (stateString==tr("Переменная")) //Если идентификатор
{
if (!identifiers.contains(text)) //если данный идентификатор встречается первый раз
{
identifiersCnt++; //счетчик идентификаторов
identifiers.insert(text, identifiersCnt); //добавление идентификатора в таблицу идентификаторов
}
QString str;
str.setNum(identifiers.value(text));
emit showLexeme(text, stateString, str); //послать лексему в таблицу
}
else
emit showLexeme(text, stateString); //послать лексему в таблицу
lexDesc.text=text; //текст
lexDesc.type=type; //тип лексемы
lexDesc.stringNumber=stringNumber; //номер строки, в которой находится лексема
lexemes.append(lexDesc); //добавить лексему в массив
}
SynAnalyser.h
#ifndef SYNANALYSER_H
#define SYNANALYSER_H
#define RULENUM 29
#define MAXRULELENGTH 300
#include <QObject>
#include <QVector>
#include <QMap>
#include <QStack>
#include <QChar>
class SynAnalyser : public QObject
{
Q_OBJECT
public:
SynAnalyser(QObject* parent = 0);
private:
struct lexemeDescription
{
QString text;
QString type;
int stringNumber;
};
struct synTreeItem
{
QString text;
QVector<synTreeItem*> childItems;
};
struct stackItem
{
QString text;
QString value;
synTreeItem* node;
};
synTreeItem* rootTreeItem;
synTreeItem* treeItem;
synTreeItem* treeItemChild;
QChar matrix[29][29];
QString rules[29];
lexemeDescription lexDesc;
QVector<lexemeDescription> lexemes;
QMap<QString, int> identifiers;
QStack<stackItem> stack;
stackItem sItem;
int stackSize;
int lexemesPos;
int stackPos;
void createMatrix();
void createRules();
int maxRuleLength;
void start();
QChar getMatrixValue(QString tTerm, QString fLex);
void shift(); //сдвиг
void reduce(); //свертка
QString getTopTerm();
int getTermNum(QString text);
QString topTerm;
QString curLex;
QString curRule;
QString SynAnalyser::getStackItemText();
signals:
void sendLog(QString, QString);
void setRedLine(int);
void setRootItem(synTreeItem*);
private slots:
void setError(int stringNumber);
void getLexemes(QVector<lexemeDescription>);
void getIdentifiers(QMap<QString, int>);
};
#endif //SYNANALYSER_H
SynAnalyser.cpp
#include "SynAnalyser.h"
#include <QMessageBox>
//Лексический анализатор
SynAnalyser::SynAnalyser(QObject* parent)
: QObject(parent)
{
createMatrix();
createRules();
}
//заполнение матрицы операторного предшествования
void SynAnalyser::createMatrix()
{
QChar matrixEx[29][29] = {
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*1 program*/{' ', '=', '<', '<', ' ', ' ', ' ', '<', ' ', '<', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*2 end.*/ {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '>'},
/*3 ;*/ {' ', '>', '>', '<', ' ', ' ', ' ', '<', '>', '<', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*4 if*/ {' ', ' ', ' ', ' ', '=', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '<', '<', '<', '<', '<', '<', '<', '<', ' ', '<', '<', '<', '<', ' '},
/*5 then*/ {' ', ' ', ' ', '<', ' ', '=', '=', '<', ' ', '<', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*6 else*/ {' ', ' ', ' ', '<', ' ', ' ', '=', '<', ' ', '<', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*7 endif*/ {' ', '>', '>', ' ', ' ', '>', '>', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*8 begin*/ {' ', ' ', '<', '<', ' ', ' ', ' ', '<', '=', '<', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*9 end*/ {' ', '>', '>', ' ', ' ', '>', '>', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*10 for*/ {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '=', ' ', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*11 downto*/ {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', ' ', ' ', '=', '<', '<', ' ', ' ', ' ', ' ', '<', '<', '<', '<', '<', ' ', '<', '<', '<', '<', ' '},
/*12 do */ {' ', '>', '>', '<', ' ', '>', '>', '<', '>', ' ', ' ', ' ', '<', ' ', ' ', ' ', ' ', ' ', '<', '<', '<', '<', '<', ' ', '<', '<', '<', '<', ' '},
/*13 a*/ {' ', '>', '>', ' ', '>', '>', '>', ' ', '>', ' ', '>', '>', ' ', ' ', '=', '>', ' ', ' ', '>', '>', '>', '>', ' ', '>', '>', '>', ' ', ' ', ' '},
/*14 c*/ {' ', '>', '>', ' ', '>', '>', '>', ' ', '>', ' ', '>', '>', ' ', ' ', ' ', '>', ' ', ' ', '>', '>', '>', '>', ' ', '>', '>', '>', ' ', ' ', ' '},
/*15 :=*/ {' ', '>', '>', ' ', ' ', '>', '>', ' ', ' ', ' ', '>', ' ', '<', '<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', ' ', '<', '<', ' ', ' ', ' '},
/*16 or*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '<', '<', '<', '<', '<', '<', '<', '>', '<', '<', '<', '<', ' '},
/*17 and*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '<', '<', '<', '<', '<', '<', '<', '>', '<', '<', '<', '<', ' '},
/*18 not*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', '<', '<', '<', '<', '<', '<', '>', '<', '<', '<', '<', ' '},
/*19 <*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', '<', '>', '<', '<', ' ', ' ', ' '},
/*20 >*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', '<', '>', '<', '<', ' ', ' ', ' '},
/*21 =*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', '<', '>', '<', '<', ' ', ' ', ' '},
/*22 <>*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', '<', '>', '<', '<', ' ', ' ', ' '},
/*23 (*/ {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '<', '<', '<', '<', '<', '<', '<', '<', ' ', '<', '<', '<', '<', ' '},
/*24 )*/ {' ', '>', '>', ' ', '>', '>', '>', ' ', '>', ' ', '>', '>', ' ', ' ', ' ', '>', '>', ' ', '>', '>', '>', '>', ' ', '>', '>', '>', ' ', ' ', ' '},
/*25 -*/ {' ', '>', '>', ' ', '>', '>', '>', ' ', '>', ' ', '>', '>', '<', '<', ' ', '>', '>', ' ', '>', '>', '>', '>', '<', '>', '>', '>', ' ', ' ', ' '},
/*26 +*/ {' ', '>', '>', ' ', '>', '>', '>', ' ', '>', ' ', '>', '>', '<', '<', ' ', '>', '>', ' ', '>', '>', '>', '>', '<', '>', '>', '>', ' ', ' ', ' '},
/*27 <<*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*28 >>*/ {' ', ' ', ' ', ' ', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '<', '<', ' ', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
/*29 _|_н*/ {'<', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}
};
for (int i=0; i<29; i++)
{
for (int j=0; j<29; j++)
{
matrix[i][j] = matrixEx[i][j];
}
}
}
//Правила исходной грамматики
void SynAnalyser::createRules()
{ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
QString rulesEx[29] = {"programEend.", "E", "E;E", "E;", "ifBthenEelseEendif", "ifBthenEendif", "beginEend", "forEdowntoEdoE", "E","a:=E", "E-E", "E+E", "E", "(E)", "a", "c",//правила E->...
// 16 17 18 19 20 21 22 23 24 25 26 27 28
"BorB", "B", "BandB", "B", "notB", "B", "E<E", "E>E", "E=E", "E<>E", "(B)", "E<<E", "E>>E" //правила B->...
};
for (int i=0; i<29; i++)
rules[i] = rulesEx[i];
}
//алгоритм сдвиг-свертка
void SynAnalyser::start()
{
sendLog(tr("Начало работы синтаксического анализатора"), "END");
sendLog(tr("Количество лексем: %1").arg(lexemes.size()), "EVENT");
rootTreeItem = new synTreeItem; //корневой узел дерева
int lexemesPos=0; //позиция в цепочке лексем
int stackPos=0; //позиция в стеке
int flag=0; //флаг завершения алгоритма
stack.clear(); //очистка стека
stackSize=0; //размер стека
sItem.text="["; //маркер начала строки
sItem.value="[";
stack.push(sItem); //добавляем в стек маркер начала строки
stackSize++;
sendLog(tr("В стек добавлен маркер начала строки"), "EVENT");
lexDesc.text="]"; //маркер конца строки
lexDesc.type="LINEEND";
lexemes.append(lexDesc); //добавить в конец входной цепочки маркер конца строки
sendLog(tr("В конец входной цепочки добавлен маркер конца строки"), "EVENT");
while (flag==0)
{
topTerm = getTopTerm(); //верхний терминал стека
sendLog(tr("Верхний терминал стека: %1").arg(topTerm), "EVENT");
lexDesc = lexemes.at(lexemesPos); //считываем очередную лексему
curLex = lexDesc.text; //текущий символ входной цепочки
sendLog(tr("Текущий символ входной цепочки: %1").arg(curLex), "EVENT");
if ((topTerm=="[") && (curLex=="]")) //если верхний терминал стека '[' и текущяя лексема ']', то алгоритм завершен
{
flag=1; //алгоритм завершен
rootTreeItem->text="E";
emit setRootItem(rootTreeItem); //послать указатель на корневой узел дерева
emit sendLog(tr("Выполнение синтаксического анализа успешно завершено"), "END");
}
else
{
QChar matrixValue = getMatrixValue(topTerm, getStackItemText()); //значение в ячейке матрицы предшествования
emit sendLog(tr("Отношение %1 %2 %3").arg(topTerm).arg(matrixValue).arg(curLex), "MESSAGE");
if (matrixValue==' ') //если ячейка пуста
{
setError(lexDesc.stringNumber);
emit sendLog(tr("Синтаксическая ошибка, не найдено соответствие в матрице"), "ERROR");
flag=1;
}
else if ((matrixValue=='=') || (matrixValue=='<'))
{
shift(); //сдвиг
lexemesPos++; //передвигаем считывающую головку
}
else if (matrixValue=='>')
{
reduce(); //свертка
}
else //вообще-то такого быть не должно
{
QMessageBox::critical(0, "ERROR", tr("Разработчик косяк!!"), "OK");
}
}
}
}
//сдвиг
void SynAnalyser::shift()
{
emit sendLog(tr("Сдвиг"), "END");
sItem.value=curLex;
sItem.text=getStackItemText();
sItem.node = new synTreeItem; //создаем указатель на узел дерева
sItem.node->text=sItem.value;
stack.push(sItem); //пишем текущую лексему в стек
stackSize++;
}
//свертка
void SynAnalyser::reduce()
{
emit sendLog(tr("Свертка:"), "END");
stackPos=0;
// int f=0;
curRule="";
QString curTerm; //текущий терминал (последний из добавленных в правило)
stackItem nextTerm; //терминал, который считывается в данный момент
bool isTopTerm=1; //флаг = терминал является самым верхним в стеке
QChar mtrxValue; //значение ячейки в матрице предшествования
bool ruleEnd=0; //флаг конца правила
treeItem = new synTreeItem; //создаем новый узел дерева
//для всех символов стека, начиная с вершины
while (!ruleEnd) //пока не конец правила
{
nextTerm=stack.pop(); //следующий символ вытаскиваем из верхушки стека
stackSize--;
if ((nextTerm.text=="E") || (nextTerm.text=="B")) //если нетерминал
{
curRule.prepend(nextTerm.text); //добавляем в начало текущего правила
treeItem->childItems.prepend(nextTerm.node); //добавить указатель на узел в список потомков узла
}
else //если терминал
{
if (isTopTerm) //если верхний терминал стека
{
curTerm = nextTerm.text; //делаем терминал текущим
curRule.prepend(curTerm); //добавляем терминал в начало текущего правила
treeItem->childItems.prepend(nextTerm.node); //добавить указатель на узел в список потомков узла
isTopTerm=0;
}
else //не верхний терминал
{
//если этот терминал связан с текущим символом отношением '='
if (getMatrixValue(nextTerm.text, curTerm)=='=')
{
curTerm = nextTerm.text; //делаем терминал текущим
curRule.prepend(curTerm); //добавляем терминал в начало текущего правила
treeItem->childItems.prepend(nextTerm.node); //добавить указатель на узел в список потомков узла
}
else
{
stack.push(nextTerm); //обратно добавляем неиспользованный символ в стек
stackSize++;
ruleEnd=1; //флаг конца правила
break; //выходим из цикла, правило считано
}
}
}
}
if (curRule.size()>MAXRULELENGTH)
QMessageBox::critical(0, "ERROR", tr("Превышена максимальная длина правила"), "OK");
if (!curRule.isEmpty()) //если правило не пустое, то ищем соответствующее правило
{
bool isRuleValid=0; //флаг = правило корректное
sendLog(tr("Поиск правила, соответствующего '%1'").arg(curRule), "MESSAGE");
for (int j=0; j<RULENUM; j++)
{
stackItem curRuleStruct;
if (rules[j]==curRule) //если правило совпало
//добавляем Е или В в зависимости от j
{
if (j<16) //Если правило Е (арифметическое)
{
curRuleStruct.text="E";
sendLog(tr("Соответствующее правило найдено, заменяем на 'E'"), "MESSAGE");
treeItem->text="E"; //название узла дерева
}
else //правило B (логическое)
{
curRuleStruct.text="B";
sendLog(tr("Соответствующее правило найдено, заменяем на 'B'"), "MESSAGE");
treeItem->text="B"; //название узла дерева
}
curRuleStruct.value = curRule; //значение символа
curRuleStruct.node = treeItem; //помещаем указатель на узел дерева (нетерминал)
rootTreeItem = treeItem; //на всякий случай запоминаем, как корневой узел
stack.push(curRuleStruct); //помещаем на верхушку стека нетерминал
stackSize++;
isRuleValid=1; //правило корректно
break; //выход из цикла
}
}
if (!isRuleValid) //если правило некорректно
{
QMessageBox::critical(0, "ERROR", tr("Не найдено соответствующее правило, ошибка!"), "OK");
setError(lexDesc.stringNumber); //послать сообщение о синтаксической ошибке
}
}
}
//возвращает терминал грамматики, соответствующий текущей считываемой лексеме curLex
QString SynAnalyser::getStackItemText()
{
QString type = lexDesc.type;
if (type=="CONSTANT")
return "c";
else if (type=="ID")
return "a";
else
return lexDesc.text;
}
//верхний терминал стека
QString SynAnalyser::getTopTerm()
{
QString text("");
if (stackSize<1) QMessageBox::critical(0, "ERROR", "Стек пуст!", "OK");
for (int i=stackSize-1; i>=0; i--)
{
stackItem sI;
sI = stack.at(i);
text = sI.text;
if ((text!="E") && (text!="B"))
break;
}
return text;
}
//получить номер столбца/строки терминала в матрице предшествования
int SynAnalyser::getTermNum(QString text)
{
int n;
if (text=="program")
n=0;
else if (text=="end.")
n=1;
else if (text==";")
n=2;
else if (text=="if")
n=3;
else if (text=="then")
n=4;
else if (text=="else")
n=5;
else if (text=="endif")
n=6;
else if (text=="begin")
n=7;
else if (text=="end")
n=8;
else if (text=="for")
n=9;
else if (text=="downto")
n=10;
else if (text=="do")
n=11;
else if (text=="a")
n=12;
else if (text=="c")
n=13;
else if (text==":=")
n=14;
else if (text=="or")
n=15;
else if (text=="and")
n=16;
else if (text=="not")
n=17;
else if (text=="<")
n=18;
else if (text==">")
n=19;
else if (text=="=")
n=20;
else if (text=="<>")
n=21;
else if (text=="(")
n=22;
else if (text==")")
n=23;
else if (text=="-")
n=24;
else if (text=="+")
n=25;
else if (text=="<<")
n=26;
else if (text==">>")
n=27;
else if ((text=="[") || (text=="]"))
n=28;
return n;
}
//получить значение в ячейке матрицы предшествования
QChar SynAnalyser::getMatrixValue(QString tTerm, QString fLex)
{
int i = getTermNum(tTerm); //номер строки
int j = getTermNum(fLex); //номер столбца
return matrix[i][j];
}
//сообщить об ошибке
void SynAnalyser::setError(int stringNumber)
{
QMessageBox::critical(0, "ERROR", tr("Синтаксическая ошибка в %1 строке").arg(stringNumber), "OK");
emit sendLog(tr("Синтаксическая ошибка в %1 строке").arg(stringNumber), "ERROR");
emit setRedLine(stringNumber); //выделить красным строку с ошибкой
}
void SynAnalyser::getLexemes(QVector<lexemeDescription> lexemesDesc)
{
lexemes=lexemesDesc;
sendLog(tr("Приняты лексемы от лексического анализатора"), "MESSAGE");
}
void SynAnalyser::getIdentifiers(QMap<QString, int> ids)
{
identifiers=ids;
sendLog(tr("Приняты идентификаторы от лексического анализатора"), "MESSAGE");
start(); //начать синтаксический анализ
}