Оператор
IF.
Ввел еще один параметр, отключающий при нулевом значении полезные действия (ToDoif), аналогичный ToDo. С его помощью отключается выполнение внутри IF. Я решил не задействовать для этого ToDo, так как возникло подозрение, что IF и безусловные переходы GOTO начинают «мешать» друг другу.
Приведу отрывок программы – функции IfOp и Operators (из проекта папки Gramm95_003).
/***
If **/
void IfOp()
{
int
Result;
int
ToDoif1;
char
Lex2[20];
NextLexema();
/***************/
if(*Lex!=40) /* Если скобка */
{
*Res=0;
ErrorLex(18);
/*WrStr("Error.txt",End,"ERROR - No ( after
IF",1);*/
return;
}
ToDoif1=ToDoif;
NextLexema();
expr2();
if(ToDo!=0&&ToDoif!=0)
{
PostFix(Res,dest);
Result=atoi(dest);
}
if(*Lex!=41)
{
*Res=0;
ErrorLex(19);
/*WrStr("Error.txt",End,"ERROR - No 2-nd bracket in
IF",1);*/
return;
}
if(ToDo!=0&&ToDoif!=0)
{
if(Result!=0)
{
ToDoif=1;
}
else
{
ToDoif=0;
}
/*ToDoif1=ToDoif;*/
}
NextLexema();
while(1==1)
{
GenOperators();
NextLexema();
if(COMPstr(Lex,"ENDIF")==0)
{
ToDoif=ToDoif1;
break;
}
if(*Lex==0)
{
/**Res=0;*/
/*ErrorLex(20);*/
/*WrStr("Error.txt",End,"Cannot find ENDIF",1);*/
break;
}
if(COMPstr(Lex,"ELSE")==0)
{
break;
}
}
/****ELSE******/
if(COMPstr(Lex,"ELSE")==0)
{
if(ToDo!=0&&ToDoif!=0)
{
if(Result!=0)
{
ToDoif=0;
}
else
{
ToDoif=1;
}
}
NextLexema();
while(1==1)
{
GenOperators();
NextLexema();
if(COMPstr(Lex,"ENDIF")==0)
{
ToDoif=ToDoif1;
break;
}
if(*Lex==0)
{
/**Res=0;*/
/*ErrorLex(20);*/
/*WrStr("Error.txt",End,"Cannot find ENDIF",1);*/
break;
}
}
}
/*****конец
обр-ки ELSE*******/
/*ToDoif=ToDoif1;*/
NextLexema();
/*if(*Lex!=59)
{
ErrorLex(21);
WrStr("Error.txt",End,"No ; after ENDIF(...)",1);
NextLexema();
}*/
return;
/***************/
}
/*** End of
If **/
void Operators() /* Это - собственно оператор (присваивания и др) */
{
if(COMPstr(Lex,"PRINT")==0)
{
OutPut();
return;
}
if(COMPstr(Lex,"GOTO")==0)
{
GoTo();
return;
}
if(COMPstr(Lex,";")==0)
/* Обработка пустого оп-ра */
{
return;
}
if(COMPstr(Lex,"IF")==0)
{
IfOp();
return;
}
Assignment();
}
БНФ я здесь не привожу. Дело в том, что когда я писал это место, я руководствовался не БНФ, а логикой. Далее я переписал этот кусок программы, немного изменив его (это было уже после введения WHILE). БНФ будет показана уже для окончательного варианта.
Позже (в папке Gramm95_006) я ввел счет строк для точной диагностики ошибок (глобальная переменная STR, где находится номер текущей строки программы). Но счет отрабатывался не очень точно. Я пришел к выводу, что нужно менять сканер, но этого я пока делать не буду. В конце концов номера строк – это дело далеко не первой важности. Кроме того их точное отслеживание еще не решит проблему диагностики ошибок. Сошлюсь на авторитет – приведу мнение Робина Хантера (из книги «Основные концепции компиляторов»):
«Возникновение ошибки при считывании одиннадцатого символа может быть связано как с некорректностью настоящего символа, так и с ошибкой в предыдущих символах программы, и это – одна из причин того, что сообщения об ошибках могут причинять неудобства. Это не означает, что компилятор может выдать сообщение об отсутствующей ошибке, он просто может указать неверное место ее нахождения и из-за этого неправильно ее охарактеризовать».
Так что номерами строк займемся позже, пока же будем учитывать их, если они есть в сообщении от функции ошибок, но будем относиться к этой информации с осторожностью.
Кстати, вот пример программки (на создаваемом языке) и с IF , и с безусловными переходами:
M=1;
L0: M=M+1;
PRINT("SSSSSSSSSSSSSSSSSSSSS");
J=1;
L2:J=J+1;
PRINT("AAAAAAAAAAA");
IF(J>10) GOTO L4;
ENDIF;
GOTO L2;
L4:
IF(M>5)
GOTO L1;
ENDIF;
GOTO L0;
L1:PRINT("The end!");
;;;;;;;;;;
Эта программа должна находиться в файле Pr_Str.txt.