//Аналог программы 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;
}