//Аналог программы 186.c Разница в том, что эта программа до кучи выводит входной поток.
//Программа просматривает весь текст он начала идо конца, если находит ошибку в скобках, присваивает i значение 1. Если мы заходим в комментарии, то есть обнаруживаем последовательность // или /* то переменной p присваиваем одно из таких значений:
/*
Если нашли /* то p== * (соответственно, ищем *)
если нашли /*а_через_некоторе_время_\ то p= \ (ищем любой знак кроме '\')
eсли нашли /*_через_некоторое_время_*_не_/_и_не_'\' то p= * (ищем *)
если нашли // то p= n (ищем '\n')
если нашли //_через_некоторое_время_\ то p= | (ищем любой знак кроме '\')
Кроме того, программа устроена так, что если комментарий начался /* то после каждой найденной пары \_любой_знак_кроме_'\' p присвоится значение *, то ест искать будем *. И если комментарий начался // то после каждой найденной пары \_любой_знак_кроме_'\' p присвоится значение 'n', то есть искать будем '\n'
*/
//Функции не использовал принципиально, хотя можно было. ТОгда сразу уж и рекурсию надо было- но это задание из K&R, а там рекурсия ещё не пройдена! Хотя стоп, может и не надо здесь функций никаких... Писанины будет ненамного (!) меньше зато сейчас программа последовательно выполняется и времени на её выполнение уходит вроде бы не больше, чем если бы я функции вызывал
//Текст любой кроме <ctrl+d>
#include <stdio.h>
int main () {
int c= 'k';
int f= 0, o= 0, k= 0; //Это количество скобок фигурных, обыкновенных и квадратных.
int i= 0;
char p= 'x';//Внимание! При просматривании всего текста эта штука равна x. Но она становится не равной x, как только мы заходим в комментарии
char s= 'n';//А этой переменной мы присваиваем значение "последняя найденная скобка"
c= getchar ();
putchar ©;
do {
//Вот сюда заходим если находимся вне комментариев
if (p== 'x') {
if ((c!='(')&&(c!=')')&&(c!='{')&&(c!='}')&&(c!='[')&&(c!=']')&&(c!='"')&&(c!='\'')&&(c!='/')) {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
else {
if (c== '(') {
s= c;
o= o++;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
if (c== '[') {
s= c;
k= k++;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
if (c== '{') {
s= c;
f= f++;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
//На одном примере разберём: если нами найдена обратная скобка и величина o (для каждого вида скобок своя) станет отрицательной, то это значит, что закрывающихся скобок больше, чем открывающихся, что ошибка. Если скобка, ближайшая к этой скобке и стоящая перед ней есть открывающаяся скобка другого вида, то это тоже ошибка, в том и другом случае i становится равным 1
if (c== ')') {
if ((o= o-1)< 0||(s== '{')|| (s== '[')) {
i= 1;
}
s= c;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
if (c== '}') {
if ((f= f-1)< 0||(s== '[')|| (s== '(')) {
i= 1;
}
s= c;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
if (c== ']') {
if ((k= k-1)< 0||(s== '{')|| (s== '(')) {
i= 1;
}
s= c;
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
//В этот цикл заходим, если найдём "
if (c== '"') {
//Считываем, до куда надо (см. условие)
do {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
while ((c!= '\\')&& (c!= EOF)&& (c!= '"'));
//Если спокойно дошли до конца строковой константы, просто выходим из неё и всё.
if (c== '"') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
else {
if (c=='\\') {
//ЕСли константа продолжается, считываем следующий знак и если он не '\' присваиваем с значение " и на начало. Теперь: каким бы ни был знак, стоящий после \ программа всё равно придёт на этот цикл, что нам и надо- надо ведь продолжать считывать знаки как строковую константу. Мы не можем присвоить переменной с, имеющей значение \ значение ", чтобы избежать такой ситуации: "..\" ТОгда программа пойдёт на начало придёт сюда и вторые кавычки будут трактоваться ею как окончание строковой костанты.
c= getchar ();
if (c!= EOF) {
putchar ©;
}
if (c!= EOF) {
c= '"';
}
}
}
}
//Объяснение один к одному, что и циклом выше, только там константа в двойных кавычках, а здесь в одинарных.
if (c== '\'') {
do {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
while ((c!= '\\')&& (c!= '\')&& (c!= '\''));
if (c== '\'') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
else {
if (c=='\\') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
if (c!= EOF) {
c= '\'';
}
}
}
}
//Это значит, что начинается комментарий.
if (c== '/') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
if (c!= EOF) {
if (c== '*') {
//Это если мы нашли начало /* комментария. Сейчас выйдем из этого цикла, уйдём на начало, а оттуда будем искать его конец, т. е пойдём в то место, где p== '*'
p= '*';
}
else {
if (c== '/') {
//Это если мы нашли начало // комментария. Сейчас выйдем из этого цикла, уйдём на начало, а оттуда будем искать его конец, т. е пойдём в то место, где p== 'n'
p= 'n';
}
}
}
}
//Как видно, если начался комментарий, то p стало равно * или / По выходу из этого цикла оно таким и осталось. Теперь на начало, а оттуда- в специальное место, где ищется конец комментария
}
}
//Сюда заходим, если p!= 'x'. Это означает, что начались комментарии, мы в них зашли и теперь ищем их конец.
else {
//Cюда зашли, если нашли начало /* комментария
if (p=='*') {
//Просматриваем комментарий, пока не найдём, что ищем (см. условие)
do {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
while (c!= EOF && c!= '*'&& c!= '\\');
if (c!= EOF) {
if (c== '*') {
//Ага, нашли * Теперь будем искать / Соответственно p присваиваем значение /
p= '/';
}
else {
//А это в комментарии мы нашли \ Теперь будем искать следующую '\'
p== '\\';
}
}
}
//А сюда мы зашли, если ищем / Её, напомню, ищем если осталось её найти и всё, комментарий закончился
if (p== '/') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
if (c!= EOF) {
if (c== '/') {
//Всё, если нашли / присваиваем p значение x и на начало
p= 'x';
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
else {
//Это если /**\ Это если вдруг такой вариант попадётся.
if (c== '\\') {
p= '\\';
}
else {
//ЭТо если /**_не_*_и_не_'\'_и_не_\_и_не_/
if (c!= '*') {
p= '*';
}
//Остался вариант по умолчанию. То есть если с=='*' переменная p какой была / такой и осталась
}
}
}
}
//А это значит, если комментарий начался /* а потом в нём встретилась \ Значит ищем следующую \ Переменной p присвоено соответствующее значение. На самом деле нам неважно, найдём мы её или нет. Важно, чтобы после первой \ стоял любой знак кроме '\'- она аннулирует всё. Поэтому, что бы после неё не стояло, мы после этого знака будем искать *
if (p=='\\') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
if (c!= EOF) {
p= '*';
}
}
//Тут понятно, комментарий начался // Ищем '\n'
if (p=='n') {
//Считываем до определённого момента (см. условие)
do {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
while (c!= EOF && c!= '\\'&& c!= '\n');
if (c!= EOF) {
//Это если мы спокойно считали '\n' Сейчас присвоим p значение x и пойдём на начало
if (c== '\n') {
p= 'x';
c= getchar ();
if (c!= EOF) {
putchar ©;
}
}
//А это тот случай, когда в теле комментария, начавшегося // (не /* !) была обнаружена \ Значит, нужно искать знак, который за ней следует
else {
p= '|';
}
}
}
//Сюда зашли если комментарий начался// а потом прервался '\'
if (p== '|') {
c= getchar ();
if (c!= EOF) {
putchar ©;
}
//Вот, какой бы знак сейчас ни был (кроме '\') будем искать '\n'
if (c!= EOF) {
p= 'n';
}
}
}
}
while (c!= EOF);
if(f> 0|| o> 0|| k> 0) {
i= 1;
}
if (i== 1) {
printf ("Есть ошибки\n");
}
else {
printf ("Ошибок нет\n");
}
return 0;
}