ПО, ЭВМ и АСУ из Таможенного Союза

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Лабораторный стенд

Сообщений 1 страница 30 из 33

1

В этой теме я буду показывать свои небольшие наработки, идеи, кусочки кода. В максимально простой и понятной форме. Если кто-то увидит, что показанное можно сделать проще, лучше, быстрее, компактнее, буду рад новым идеям. Если просто захочется высказаться или поглумиться:), то рядышком сделаю соответствующую тему

0

2

Какими инструментами и средствами мы располагаем на нашем "лабораторном стенде"?
ОС -Windows 10.
Язык программирования - С/С++ (я буду использовать только русифицированный С).
Компиляторы - tcc, gcc.
Для русификации использован транспилятор Юрия, только модифицированный.
Об остальных инструментах буду рассказывать по мере необходимости.

А начну с ясельной группы детского сада. С "Hello world" Ну, в нашем случае напишем: "Лабораторный стенд"

Отредактировано Евгений (2022-05-03 20:31:56)

0

3

#вставка <locale.h>   //Во избежание "крокозяблей" на выводе
#вставка <stdlib.h>
#вставка <wchar.h>
   //"Широкие" многобайтовые символы и их ввод-вывод
#вставка <wctype.h> //"Классификация" широких символов

//Переопределенные функции и типы. Понадобятся в будущем
#макрос пчтф16( ... )   wprintf(  __VA_ARGS__ )
#макрос читз16()        getwchar()
#макрос симв16          wchar_t

цел main()   
{
      // В нашем коде будет очень мало строк с использованием латиницы
      // И следующие строки как раз исключение из правила

      setlocale(LC_ALL, "");    // установка локали
      system("cls");              // очистка экрана

      симв16 строка_приветствия[] = L"Лабораторный стенд";

      пчтф16(строка_приветствия); // вывод в окно консоли
      читз16();        // пауза
}

Отредактировано Евгений (2022-05-03 20:40:25)

0

4

Чуть больше года назад я впервые увидел код на русском. Честно говоря впечатления от увиденного были неоднозначные. Код выглядел непривычно, если не сказать отталкивающе... Забегая вперед, хочу сказать, что сейчас, через год, я не хочу возвращаться к стандарту. Лично для меня писать код с русскими идентификаторами и русскими ключевыми словами приятнее и комфортнее. Однако транспилятор это лишь костыль, который позволяет решить часть проблем. Надеюсь, когда-нибудь появится полноценный язык программирования с полной поддержкой русского языка и с широкими возможностями.

Теперь для чего я привел детский пример, да еще заморочился раскрасить код в разные цвета. На самом деле подсветка синтаксиса вещь очень полезная, очень сильно влияющая на восприятие кода. Особенно непривычного кода. Если кто-то думает, что сделать подсветку кода на кириллице легко и с этим справится почти любая IDE, то попробовав на практике, боюсь этот человек будет обескуражен. То тут, то там вылезают неожиданные "грабли", обойти которые не удается. Лично я нашел лишь один редактор, который справился с задачей блестяще и скорее всего потому, что его автор наш соотечественник. В следующий раз я расскажу об этом редакторе и о том, как настроить в нем подсветку синтаксиса для тех примеров, которые я буду показывать дальше.

0

5

А вот примерно так выглядит код в окне моего редактора:

Пока руками готовил пример подсветки, пришла в голову мысль: а пусть первой лабораторной работой будет программа, которая сможет из куска кода сделать html-текст с подсветкой, как в программном редакторе.
Все по-честному: никаких сторонних библиотек, регулярных выражений. Лексер на голом С и последующая генерация html-кода.

0

6

NuShaman написал(а):

А на Паскале можно,
в среде разработки "Borland Delphi 7"
под "Windows 10"
или низзя?

Можно. Я показываю идеи, Вы реализовываете. И просьба - я хочу оставить в этой ветке полезные, на мой взгляд вещи, в концентрированном виде. Любые вопросы, пожелания, обсуждения кладите в соседнюю ветку.

0

7

Программа подсветки синтаксиса для форума.
Состоять она будет из отдельных кусочков и соответственно этапов:
1. Считываем файл целиком в буфер.
        Вроде по правилам нужно считывать в небольшой буфер, с которым уже может работать лексер,
        но у нас еще впереди развлечение с кодировками. Поэтому будем делать, как проще и понятнее.
2. Разбираемся с кодировками и приводим к UTF-16
        Почему UTF-16? Удобно.
3. Полученный UTF-16 текст обрабатываем лексером (лексическим анализатором)
        Лексер будет заточен под двуязычный синтаксис С/С++. То есть одинаково будут обрабатываться,
        как стандартные конструкции, так и русифицированные.
4. Анализируем выданные лексером токены и формируем выходной текст обрамляя нужные лексемы html- тэгами.
        Область html для меня темная, будем разбираться по ходу пьесы.
5. Попутно нужно будет решить вопрос с выходной кодировкой.

Когда у нас будет лексер, мы подойдем к вопросу токенов, массивов, узлов и деревьев. Я не хочу торопить события. У меня уже есть готовый лексер, но я хочу изменить в нем некоторые моменты.
А чтобы потом это все хорошо стыковалось будем делать последовательно. Но идея такова: токен это почти узел дерева, только без связей. Лексер укладывает токены в массив-дерево последовательно один за другим
Парсер пробегая по этому же массиву лишь формирует связи, родительские и дочерние. И таким образом из массива мы получаем дерево.

0

8

Сначала хотел выкладывать лишь интересные кусочки. Но сейчас прихожу к выводу, что первый проект имеет смысл разобрать полностью. Даже малозначительные вещи.
Подсветки кода пока нет, так что будет не очень удобно. Начнем со скучных, но необходимых вещей. Поскольку предстоит работать с файлами и памятью, то начнем сразу с обработки ошибок.
Файл error.rh

Код:
#если_нет 	ERROR_H
#макрос	  	ERROR_H	
//===========================================================
// 	Файл:    error.rh
// 	Версия:    1.01
// 	Дата:    18:17 05.05.2022
//	Описание:	Объявление функций печатающих сообщения об
//        ошибках, предупреждениях и тд.
//	Автор:
//===========================================================
//===========================================================
//	Фунция печатает сообщение об ошибке и возвращает код
//  ошибки. 
//===========================================================
цел сообщение_об_ошибке (цел код_ошибки);

//===========================================================
//	Фунция печатает сообщение об ошибке и имя файла. 
// 	Возвращает код ошибки. 
//===========================================================
цел сообщение_об_ошибке_в_файле (цел код_ошибки, симв *имя_файла);


#к_если    //ERROR_H

0

9

В  следующем файле мы пишем реализацию функций объявленных выше. Первая просто выводит текст ошибки. Во второй к нему добавляется имя файла.
Файл error.r

Код:
 //===========================================================
// 	Файл:    error.r
// 	Версия:    1.01
// 	Дата:    18:17 05.05.2022
//	Описание:	Определение функций печатающих сообщения об
//        ошибках, предупреждениях и тд.
//	Автор:
//===========================================================
#вставка	"error.h"
#вставка	"messages.h"
#вставка	"library.h"

//===========================================================
//	Фунция печатает сообщение об ошибке и возвращает код
//  ошибки. 
//===========================================================
цел сообщение_об_ошибке (цел код_ошибки)
{
  	// пишем в стандартный поток ошибок
  	fwprintf(stderr, L"Ошибка: %s", таблица_сообщений[код_ошибки]);
	вернуть код_ошибки;
}
//===========================================================
//	Фунция печатает сообщение об ошибке и имя файла. 
// 	Возвращает код ошибки. 
//===========================================================
цел сообщение_об_ошибке_в_файле (цел код_ошибки, симв *имя_файла)
{
  	// пишем в стандартный поток ошибок
  	fwprintf(stderr, L"Ошибка: %s", таблица_сообщений[код_ошибки]);
	fprintf(stderr, имя_файла);
	вернуть код_ошибки;
}

Отредактировано Евгений (2022-05-05 21:21:44)

0

10

В следующем файле просто таблица сообщений используемых для вывода ошибок.
Файл messges.rh

Код:
#если_нет 	MESSAGES_H 
#макрос     MESSAGES_H 
#вставка	"library.h"


//==========================================================================
//	Таблица сообщений, которые выводятся при ошибках и пр. ситуациях
//==========================================================================

симв16*	таблица_сообщений[] = {
/*  0 */	 L"Без ошибок\n"
/*  1 */	,L"пустое имя файла\n"
/*  2 */	,L"ошибка в командной строке\n"
/*  3 */	,L"не возможно выделить/расширить память\n"
/*  4 */	,L"не возможно открыть "
/*  5 */	,L"пустой файл "
/*  6 */	,L"не возможно прочитать "
/*  7 */	,L"не возможно записать "
/*  8 */	,L"не возможно использовать "
/*  9 */	,L"совпадает имя входного и выходного файла "
/* 10 */	,L"резерв\n"

};

//------------------------------------------------------------------------
#к_если  //MESSAGES_H

0

11

Ну и перечень кодов ошибок. Файл ercode.rh

Код:
#если_нет ERCODE_H
#макрос ERCODE_H


#макрос 	НЕТ_ОШИБОК                    0
#макрос 	ОШИБКА_ПУСТОЕ_ИМЯ             1
#макрос 	ОШИБКА_В_КОМАНДНОЙ_СТРОКЕ     2
#макрос 	ОШИБКА_ВЫДЕЛЕНИЯ_ПАМЯТИ       3
#макрос 	ОШИБКА_НЕ_ОТКРЫТЬ             4
#макрос 	ОШИБКА_ПУСТОЙ_ФАЙЛ            5
#макрос 	ОШИБКА_НЕ_ПРОЧИТАТЬ           6
#макрос 	ОШИБКА_НЕ_ЗАПИСАТЬ            7
#макрос 	ОШИБКА_НЕВОЗМОЖНО_ИСПОЛЬЗОВАТЬ 8
#макрос 	ОШИБКА_СОВПАДАЮЩИЕ_ИМЕНА      9


#к_если  //ERCODE_H

0

12

Теперь более интересные вещи. Нам нужен удобный текстовый буфер с поддержкой операций чтения из файла, записи в файл, выделения и очистки памяти. Память выделяется динамически, приходится об этом заботится.
Файл textbuffer.rh

Код:
#если_нет TEXTBUFFER_H
#макрос TEXTBUFFER_H

#вставка	"library.h"
#вставка	"ercode.h"

//=======================================================
// Структура, описывающая текстовый буфер
//=======================================================
тип структура{

     б8  *текст;
 симв16  *текст16;
   симв  *имя_файла;
    ц64   длина_текста;	
    ц64   длина_текста16;
    ц32   флаг_сообщений;    
}  ТБуфер;
//=======================================================
// Необходимые функции, для работы с текстовым буфером
//=======================================================
цел       файл_в_буфер ( ТБуфер* буф );
цел       буфер_в_файл ( ТБуфер* буф );
цел    дописать_в_файл ( ТБуфер* буф );
цел    выделить_память ( ТБуфер* буф, ц64 длина );
пуст освободить_память ( ТБуфер* буф );
цел    расширить_память( ТБуфер* буф, ц64 длина);


#к_если  //TEXTBUFFER_H

Отредактировано Евгений (2022-05-06 14:45:43)

0

13

А теперь реализация этих функций.
Файл textbuffer.r

Код:
 
#вставка	"textbuffer.h"
#вставка	"error.h"
//==========================================================================
// Функция определяет размер открытого файла, переместив указатель в конец
// Затем указатель возвращается к началу файла
//==========================================================================

ц64	вернуть_длину_файла (FILE *файл) 
{
	fpos_t	позиция = 0;    // tcc Compiler
	fseek(файл, позиция, SEEK_END); 
	fgetpos(файл, &позиция);
	fseek(файл, 0L, SEEK_SET);	
	ц64	врем_длина = (ц64) позиция;
	вернуть	врем_длина;
} 

//==========================================================================
// Функция выделяет память
//==========================================================================
цел выделить_память(ТБуфер* буф, ц64 длина)
{
    цел ошибка = НЕТ_ОШИБОК;
	если(буф->текст != НОЛЬ){
    //значит память была выделена раньше
    вернуть  сообщение_об_ошибке(ОШИБКА_ВЫДЕЛЕНИЯ_ПАМЯТИ);
    }
    буф->текст = (беззнак симв *) malloc(длина);
    вернуть ошибка;
}
//==========================================================================
// Функция расширяет выделенную память
//==========================================================================
цел расширить_память(ТБуфер* буф, ц64 длина)
{
    цел ошибка = НЕТ_ОШИБОК;
	если(буф->текст != НОЛЬ){
    //значит память была выделена раньше
    вернуть  сообщение_об_ошибке(ОШИБКА_ВЫДЕЛЕНИЯ_ПАМЯТИ);
    }
    буф->текст = (беззнак симв *) realloc(буф->текст, длина);
    вернуть ошибка;
}

//==========================================================================
// Функция очищает память, выделенную при загрузке из файла
// или выделенную специально
//==========================================================================
пуст освободить_память ( ТБуфер* буф)
{
	free (буф->текст);
	буф->текст = НОЛЬ;
	free (буф->текст16);
	буф->текст16 = НОЛЬ;
	
}

//==========================================================================
// Функция открывает файл, выделяет место в памяти для буфера
// и считывает символьные данные в буфер. Выделенная память освобождается
// в конце программы
//==========================================================================
цел файл_в_буфер( ТБуфер* буф)
{
	цел ошибка = НЕТ_ОШИБОК;
	если (буф->имя_файла == НОЛЬ){
    вернуть  сообщение_об_ошибке(ОШИБКА_ПУСТОЕ_ИМЯ);
	}
	// Пытаемся открыть имя_файла
    буф->длина_текста = 0;
    FILE* файл = fopen(буф-> имя_файла, "rb");
    если (! файл){
    // если не получилось
    вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ОТКРЫТЬ,буф->имя_файла);
	}
	
    буф->длина_текста = вернуть_длину_файла(файл);
    если(буф->длина_текста <= 0)
    {
        // если пустой
        fclose(файл );
        вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_ПУСТОЙ_ФАЙЛ,буф->имя_файла);
    }
    // если файл не пустой, пытаемся выделить память
	ошибка = выделить_память(буф, буф->длина_текста + 1);
	если(ошибка){
    вернуть ошибка;
	}
	// если память выделена успешно, пытаемся читать	
    если(fread((void *) буф->текст, буф->длина_текста, 1, файл) != 1)
    {
        //если не удачно, закрываем файл, освобождаем память
        fclose(файл );
        освободить_память(буф);
        вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ПРОЧИТАТЬ,буф->имя_файла);
        
    }
    буф->текст[буф->длина_текста] = '\0'; // на всякий случай
    fclose(файл );
    вернуть ошибка;
    // Закончили работу с файл
}

//==============================================================
// Записываем текст в файл
//==============================================================
цел буфер_в_файл ( ТБуфер* буф)
{	
	цел ошибка = НЕТ_ОШИБОК;
	если (буф->имя_файла == НОЛЬ){
    вернуть  сообщение_об_ошибке(ОШИБКА_ПУСТОЕ_ИМЯ);
	}	
	FILE* файл  = fopen (буф->имя_файла, "wb");
	если (! файл){
    // если не получилось
    вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ОТКРЫТЬ,буф->имя_файла);
	}
	если ( fwrite ((void*) буф->текст, буф->длина_текста, 1, файл ) !=1) 
	{
    вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ЗАПИСАТЬ,буф->имя_файла);
    }
	fclose(файл );
	вернуть ошибка;
}

//==============================================================
// Дописываем текст в конец файла
//==============================================================
цел дописать_в_файл( ТБуфер* буф)
{
	цел ошибка = НЕТ_ОШИБОК;
    если (буф->имя_файла == НОЛЬ){
    вернуть  сообщение_об_ошибке(ОШИБКА_ПУСТОЕ_ИМЯ);
	}
    FILE* файл  = fopen(буф->имя_файла, "ab");
    
    если (! файл){
    // если не получилось
    вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ОТКРЫТЬ,буф->имя_файла);
	}
    если(fwrite((void *) буф->текст, буф->длина_текста, 1, файл) != 1)
    {
    вернуть  сообщение_об_ошибке_в_файле(ОШИБКА_НЕ_ЗАПИСАТЬ,буф->имя_файла);
    }
    fclose(файл);
    вернуть ошибка;
}

0

14

С первым пунктом нашей программы мы успешно справились. Впереди у нас развлечения с кодировками. Будем предполагать, что возможны три входные кодировки: СР866, СР1251 и UTF-8. Наша программа должна автоматически определить кодировку и перекодировать в UTF-16.
В нашем буфере есть два члена структуры: текст и текст16. В первый мы будем считывать содержимое файла, а во второй помещать результат перекодировки.

0

15

По традиции сначала файл с объявлениями. Файл code_utf16.rh

Код:
#если_нет 	CODE1251_H
#макрос 	CODE1251_H


#вставка "textbuffer.h"
#вставка	"library.h"

//==========================================================================
// Функция приводит кодировку к ср1251
//==========================================================================
цел  перекодировать_в_cp1251 ( ТБуфер* буф);	// переписывание "на месте"
цел  перекодировать_в_UTF16( ТБуфер* буф);	

#к_если // CODE1251_H

0

16

И сама реализация. Код уже более объемный. Если кто захочет вникнуть - запасайтесь таблицами кодировки) Несмотря на некоторую "неуклюжесть" кода, работает очень шустро.
Файл code_utf16.r

Код:
#вставка	"code_utf16.h"	
#вставка 	<stdlib.h>

#определить   max(x,y)    (x) > (y) ? (x): (y)
#определить   CP866    0
#определить   CP1251	1
#определить   UTF8    2 

//==========================================================================
// Функция определяет кодировку 
//==========================================================================
цел  каких_символов_больше(беззнак симв*  buf, цел  длина)
{	// подсчёт символов в cp886, cp1251 и utf-8 кодировках; возвращает 0 для cp866, 1 для cp1251, 2 для utf-8
	цел  i = 0, cp866 = 0, cp1251 = 0, utf8 = 0, d0d1 = 0;
	
	для (; i < длина; ++i)
	{	
    беззнак цел  c = buf[i];
	
    если ((0xc0 <= c && c <= 0xff) || c == 0xa8 || c == 0xb8)
    	++ cp1251;
    если ((0x80 <= c && c <= 0xaf) || (0xe0 <= c && c <= 0xef) || c == 0xf0 || c == 0xf1)
    	++ cp866;
    беззнак цел  cc = buf[i+1];
    если ((c == 0xd0) && ((0x90 <= cc && cc <= 0xbf) || cc == 0x81)) {
    	++ utf8;
    	++ d0d1;	// символы, начинающиеся на d0 или d1, это буквы Р и С в cp1251
    }
    если ((c == 0xd1) && ((0x80 <= cc && cc <= 0x8f) || cc == 0x91)) {
    	++ utf8;
    	++ d0d1;
    }
    
	}
//	d(cp866);
//	d(cp1251);
//	d(utf8);
//	d(d0d1);
	цел  максимальное = max (cp866, cp1251);
	если (cp1251 == максимальное) {
    cp1251 -= d0d1;    	// уменьшить на количество букв Р и С (с кодами d0 и d1)
    максимальное = max (utf8, cp1251);
    если (utf8 == максимальное)
    	вернуть  UTF8;
    вернуть  CP1251;
	}
	вернуть  CP866;
}
//==========================================================================
// Функция приводит кодировку к ср1251
//==========================================================================

цел  перекодировать_в_cp1251 ( ТБуфер* буф)	// переписывание "на месте"
{
	
	цел  кодировка_исходника = каких_символов_больше(буф->текст, буф->длина_текста);
	цел  i=0;
	
	если (кодировка_исходника == CP1251)
    вернуть  буф->длина_текста;
	
	
	если (кодировка_исходника == UTF8) {
    цел  i = 0;
    если (буф->текст[0] == 0xEF && буф->текст[1] == 0xBB && буф->текст[2] == 0xBF)
    	i += 3;        // пропустить 16'EFBBBF'

    цел  j;
    для (j = 0; i < буф->длина_текста; ++ j) {
    	беззнак цел  c = буф->текст[i];
    	беззнак цел  cc = буф->текст[i+1];
    	если (c == 0xd0 && (0x90 <= cc && cc <= 0xbf)) {	// А-п
        буф->текст[j] = cc + 0x30;
        i += 2;
        continue;
    	}
    	если (c == 0xd1 && (0x80 <= cc && cc <= 0x8f)) {	// р-я
        буф->текст[j] = cc + 0x70;
        i += 2;
        continue;
    	}
    	если (c == 0xd0 && cc == 0x81) {	// Ё
        буф->текст[j] = 0xa8;
        i += 2;
        continue;
    	}
    	если (c == 0xd1 && cc == 0x91) {	// ё
        буф->текст[j] = 0xb8;
        i += 2;
        continue;
    	}
    //	если (c == 0x21 && cc == 0x16) {	// №
    	если (c == 0xe2 && cc == 0x84) 	// №
    	    если (буф->текст[i+2] == 0x96){
        	буф->текст[j] = 0xb9;
        	i += 3;
        	continue;
    	}
    	буф->текст[j] = c;
    	++ i;
    }
    буф->длина_текста = j;
    вернуть  j;
	}	
	// если кодировка СР866
	для (; i < буф->длина_текста; ++i) {
    беззнак цел  c = буф->текст[i];
    если ((0x80 <= c) && (c <= 0xBF))    // dos ==> win, только кириллица русского языка
    	c += 0x40;
    иначе
    {	если ((0xE0 <= c) && (c <= 0xEF))
        c += 0x10;
    	иначе
    	{	если (c == 0xF0)
        	c = 0xA8;
        иначе
        {	если (c == 0xF1)
            c = 0xB8;
        	иначе
        	{	если (c == 0xFC)    // №
            	c = 0xB9;
    }	}	}	}
буф->текст[i] = c;
	}
	вернуть  буф->длина_текста;        
}
//==========================================================================
// Функция приводит кодировку к UTF-16
//==========================================================================

цел  перекодировать_в_UTF16( ТБуфер* буф)	// переписывание "на месте"
{
	цел  кодировка_исходника = каких_символов_больше(буф->текст, буф->длина_текста);
	//если (кодировка_исходника == CP1251)
	//	вернуть  буф->длина_текста;
	
	цел  i=0;
	цел  j;
	если (кодировка_исходника == CP1251) {
    для (i = 0; i < буф->длина_текста; ++ i) {
    	беззнак цел  c = буф->текст[i];
    	
    	если (c >=0xC0 ) {	
        буф->текст16[i] = c + 0x350;
        continue;
    	}
    	если (c == 0xa8 ) {	// Ё
        буф->текст16[i] = 0x0401;
        continue;
    	}
    	если (c == 0xb8) {	// ё
        буф->текст16[i] = 0x0451;
        continue;
    	}
    //	если (c == 0x21 && cc == 0x16) {	// №
    	если (c == 0xb9) {	// №
    	   	буф->текст16[i] = 0x2116;
        continue;
    	}
    	буф->текст16[i] = c;
    	
    }
    //буф->длина_текста = j;
    буф->текст16[i] = 0;
    буф->длина_текста16 = i;
    вернуть  i;
	}
	
	если (кодировка_исходника == UTF8) {
	цел  i = 0;
    если (буф->текст[0] == 0xEF && буф->текст[1] == 0xBB && буф->текст[2] == 0xBF)
    	i += 3;        // пропустить 16'EFBBBF'

    для (j = 0; i < буф->длина_текста; ++ j) {
    	беззнак цел  c = буф->текст[i];
    	беззнак цел  cc = буф->текст[i+1];
    	если (c == 0xd0 && (0x90 <= cc && cc <= 0xbf)) {	// А-п
        буф->текст16[j] = cc + 0x380;
        i += 2;
        continue;
    	}
    	если (c == 0xd1 && (0x80 <= cc && cc <= 0x8f)) {	// р-я
        буф->текст16[j] = cc + 0x3C0;
        i += 2;
        continue; 
    	}
    	если (c == 0xd0 && cc == 0x81) {	// Ё
        буф->текст16[j] = 0x0401;
        i += 2;
        continue;
    	}
    	если (c == 0xd1 && cc == 0x91) {	// ё
        буф->текст16[j] = 0x0451;
        i += 2;
        continue;
    	}
    //	если (c == 0x21 && cc == 0x16) {	// №
    	если (c == 0xe2 && cc == 0x84) 	// №
    	    если (буф->текст[i+2] == 0x96){
        	буф->текст16[j] = 0x2116;
        	i += 3;
        	continue;
    	}
    	буф->текст16[j] = c;
    	++ i;
    }
    //буф->длина_текста = j;
    буф->текст16[j] = 0;
    буф->длина_текста16 = j;
    
    вернуть  j; 
	}
    // Если кодировка СР866
    для (i = 0; i < буф->длина_текста; ++ i) {
    	беззнак цел  c = буф->текст[i];
    	если ((0x80 <= c) && (c <= 0xBF)){    // dos ==> win, только кириллица русского языка
        буф->текст16[i] = c + 0x390;
        continue;
    	}
    	если ((0xE0 <= c) && (c <= 0xEF)){
        буф->текст16[i] = c + 0x360;
        continue;
    	}	
    	если (c == 0xF0 ) {	// Ё
        буф->текст16[i] = 0x0401;
        continue;
    	}
    	если (c == 0xF1) {	// ё
        буф->текст16[i] = 0x0451;
        continue;
    	}
    	если (c == 0xFC) {	// №
    	   	буф->текст16[i] = 0x2116;
        continue;
    	}
    	буф->текст16[i] = c;
    	
    }
    //буф->длина_текста = j;
    буф->текст16[i] = 0;
    
	буф->длина_текста16 = i;
	вернуть i;
	
	
}

0

17

Здесь хочу сказать, что многое из того, что показываю, я почерпнул из исходников транспилятора Юрия с compiler.su. В частности работа с кодировками и идеи, заложенные в лексер берут корни из его исходников.

Да, и еще... Если вдруг кто-то захочет не только почитать, но и "пощупать" наш проект руками, маякните. Дело в том, что имеется некоторый порог вхождения и мне нужно будет объяснить как и что настроить, чтобы было удобно. Кроме редактора AkelPad, нужен будет компилятор С, gcc или tcc. И кроме того понадобится утилита сборки make.

Отредактировано Евгений (2022-05-05 23:17:07)

0

18

Вот мы уже подошли вплотную к реализации лексера. Здесь имеет смысл конкретизировать нашу задачу, так как от этого будет зависеть реализация.
Нужно сказать, что лексер для подсветки будет отличаться от лексера для языка программирования. Отличаться он будет на величину комментариев.
Для нашего лексера комментарии, а также пробельные символы очень важны, тогда как для лексера ЯП эти элементы игнорируются.
Вообще, в вопросе подсветки кода каких-то стандартов нет, по крайней мере о них мне не известно. Да даже если бы было известно, я предпочту сделать, как мне нравится.
Чистой воды вкусовщина.) То есть, все определяется субъективными желаниями, объективными возможностями и изощренностью исполнителей.
Теперь конкретика. В коде мы хотим выделить следующие элементы:
1. Комментарии
2. Строковые и символьные константы ("это строка", 'А')
3. Числовые константы (12345, 0b010111, 0x2A3F  и русифицированный вариант 2"010111, 16"2A3F. Кроме того допустим знак подчеркивания в числовой константе 2"0000_1111.
До использования русских букв АБЦДЕФ в шестнадцатиричных константах я пока не созрел, но склоняюсь к этому варианту)
4. Директивы препроцессора. Начинаются с символа #. Продолжаются до конца строки или до начала комментария.
5. Операторы языка (если, иначе, для, пока, if, else, for, while и т.д.)
6. Встроенные типы и уточнения типов (цел, плав, симв, симв16, беззнак, int, float, double, char, unsigned и т.д.)
7. Остальные зарезервированные слова (объединение, перечисление, класс, структура, статич, class, struct, auto, static и т.д.)
8. Знаки операций и скобки ( []{}=+-* и т.д.)

И тут мне в голову пришла мысль... А еще я хочу выделить функции! Со стороны лексера это ИДЕНТИФИКАТОР + '('. И эта мысль резко рушит мои первоначальные планы.
Дело в том, что для идентификации функции нужен не только текущий токен, но и следующий... Изначально я хотел проделать все за один проход, без запоминания токенов и
каких-либо усложнений. С другой стороны я слишком ленив, чтобы сначала сделать простой вариант, а потом полностью переделывать на более сложный, ради одной прихоти.
Короче, делаем по полной и сразу. Поскольку токены нужно будет хранить, то сразу подойдем к массиву-дереву.
9. Функции

У меня созрел вопрос к аудитории... А достаточно ли понятно я излагаю свои мысли? Я понимаю, что кому-то любопытно, кому-то совершенно не интересно, для кого-то это примитивно и банально.
Как всегда Ваше мнение жду в соседней ветке.

0

19

Продолжим наши изыскания и попробуем порассуждать. Пока без кода. Для работы лексера нам нужны два объекта или, если хотите, две структуры.
Первый это буфер с символами. Он у нас уже есть. Второй некий массив токенов, куда лексер будет записывать результаты своей работы. Состав токена очень простой. Это целочисленная переменная,
определяющая тип токена и лексема, или строка, в которой хранится кусочек исходной последовательности символов. Чтобы не копировать строки, договоримся, что будем запоминать лишь адрес начала
лексемы в исходном буфере и количество символов, составляющих лексему. Почти структура с тремя членами.
Теперь рассмотрим узел синтаксического дерева. В его состав должны войти: тип узла, лексема, индекс родительского узла, количество дочерних узлов и массив индексов дочерних узлов.
Для семантического анализа понадобится еще несколько атрибутов узла, но для нас они сейчас не нужны. Таким образом мы видим, что токен вполне "укладывается" в узел и никаких других сущностей
придумывать не нужно. Но нам нужен не один токен-узел, а целый массив. Значит наше дерево узлов изначально должно быть массивом. Этот массив должен уметь раширяться при добавлении токенов/узлов.
Теперь опишем узел в виде структуры.

Код:
//=======================================================
// Обобщенный узел дерева
//=======================================================
тип структура {
  цел тип_узла;            // договоримся, что тип_узла и тип_токена одно и то же
                  	// и будем использовать один термин
  симв16 * лексема;        	//указатель на лексему
  цел длина_лексемы;
  
  б64 всего_доч;        	// всего дочерних узлов
  б64 родитель;            // индекс родителя
  
  б64 статич_дочерние[2];    	// статический массив на два индекса, левый и правый
  б64 *дочерние;            // указатель на массив дочерних узлов. Изначально ссылается на 
                  	// статический массив, но если нужно будет больше двух узлов, то создадим
                  	// динамический массив и скопируем в него два первых индекса из статического
  б64 длина_динамич_массива;    	// Придется хранить, никуда не деться. Можно ужать в статический массив,
                  	// но стоит ли...
   	
} Тузел; 

Немного отличается от того, что я показывал первый раз. Обращаться к дочерним через "левый" и "правый" удобно, но для унификации будем делать это через массив дочерних узлов.
Относительно первой реализации чуть проиграли в памяти, но выиграли в удобстве. Думаю, нет смысла ужиматься без меры. Дерево теперь будет выглядет так:

Код:
//=========================================================
// AST - дерево
//=========================================================
тип структура {
  Тузел *узлы;
  б64 длина_массива;	// размер массива
  
  б64 индекс_узла;    // текущий индекс узела
  б64 всего_узлов;    // количество узлов в дереве
  
  б64 индекс_токена;	// текущий индекс токена
  б64 всего_токенов;	// количество токенов в дереве
  
} ТАСД;

Маленькое замечание по дереву. Нулевой узел на заполняется токеном. Это будет стартовый узел (корень дерева)

Отредактировано Евгений (2022-05-07 18:06:40)

0

20

Наш проект продолжает неуклонно двигаться вперед. В проекте появилось еще четыре новых файла. Два файла с объявлениями и реализацией работы с деревом-массивом. Пока только та часть, которая касается работы с токенами. Работа с узлами и построение дерева в этом проекте нам не нужны. Еще добавлен файл со значениями токенов (будет еще изменяться). И файл с таблицей строк, где записаны названия токенов (для отладки). Вот теперь мы точно готовы начать писать наш лексер.
По традиции файл с объявлениями ASTtree.rh

Код:
#если_нет 	ASTTREE_H
#макрос	  	ASTTREE_H	
//===========================================================
// 	Файл:     ASTtree.rh
// 	Версия:    1.01
// 	Дата:    23:42 06.05.2022
//	Описание:
//	Автор:
//===========================================================
#вставка	"library.h"
#вставка	"ercode.h"
#вставка	"error.h"
#вставка	"tokens.h"

//=======================================================
// Обобщенный узел дерева
//=======================================================
тип структура {
  цел тип_узла;            // договоримся, что тип_узла и тип_токена одно и то же
                  	// и будем использовать один термин
  симв16 * лексема;        	// указатель на лексему
  цел длина_лексемы;
  
  б64 всего_доч;        	// всего дочерних узлов
  б64 родитель;            // индекс родителя
  
  б64 статич_дочерние[2];    	// статический массив на два индекса, левый и правый
  б64 *дочерние;            // указатель на массив дочерних узлов. Изначально ссылается на 
                  	// статический массив, но если нужно будет больше двух узлов, то создадим
                  	// динамический массив и скопируем в него два первых индекса из статического
  б64 длина_динамич_массива;    	// Придется хранить, никуда не деться. Можно ужать в статический массив,
                  	// но стоит ли...
   	
} Тузел; 

//=========================================================
// AST - дерево
//=========================================================
тип структура {
  Тузел *узлы;
  б64 длина_массива;	// размер массива
  
  б64 индекс_узла;    // текущий индекс узела
  б64 всего_узл;    // количество узлов в дереве
  
  б64 индекс_токена;	// текущий индекс токена
  б64 всего_токенов;	// количество токенов в дереве
  
} ТАСД;

//==========================================================
// Начальная инициализация AST - дерева
//==========================================================
цел АСДподготовить(ТАСД *дерево);
//==========================================================
// Освобождение памяти AST - дерева
//==========================================================
цел АСДосвободить_память(ТАСД *дерево);

//==========================================================
// Добавляем токен в массив
//==========================================================
цел АСДдобавить_токен(ТАСД *дерево, цел тип_токена, симв16 *лексема, б64 длина_лексемы);
//==========================================================
// Возращает тип текущего/следующего/послеследующего токена
// Эти три функции потом перепишем для ускорения
//==========================================================
цел АСДтокен (ТАСД *дерево);
цел АСДтокен1(ТАСД *дерево);
цел АСДтокен2(ТАСД *дерево);
//==========================================================
// Функция для отладки
//==========================================================
цел АСДраспечатать_все_токены(ТАСД *дерево);



#к_если    //ASTTREE_H

И файл с реализацией: ASTtree.r

Код:
//===========================================================
// 	Файл:    ASTtree.r
// 	Версия:    1.01
// 	Дата:    10:44 07.05.2022
//	Описание:	Определение функций работы с синтаксическим деревом
//        и массивом токенов
//	Автор:
//===========================================================
#вставка	"ASTtree.h"
#вставка	"token_names.h"    //таблица строк с наименованиями токенов
//==========================================================
// Начальная инициализация AST - дерева
//==========================================================
цел АСДподготовить(ТАСД *дерево)
{
	если (дерево->узлы == NULL)
    дерево-> узлы = (Тузел*) malloc( 10000L * sizeof(Тузел) ); //выделяем память на 10000 узлов
	иначе
    вернуть  сообщение_об_ошибке(ОШИБКА_СОЗДАНИЯ_ДЕРЕВА);	//память уже выделена ранее	
	дерево -> длина_массива = 10000L;
	дерево -> всего_узл = 1;
	дерево -> индекс_узла = 0;
	дерево -> всего_токенов = 1;
	дерево -> индекс_токена = 1;
	дерево->узлы[0].тип_узла = 0;
	дерево->узлы[0].всего_доч = 0;
	вернуть 0; 	// без ошибок
}
//==========================================================
// Освобождение памяти AST - дерева
//==========================================================
цел АСДосвободить_память(ТАСД *дерево)
{
	//********************************************
	// Сначала нужно пробежаться по узлам и при 
	// необходимости освободить память дочерние
	//********************************************
	если (дерево->узлы != NULL){
    free(дерево-> узлы); //освобождаем память
    дерево->узлы = NULL;
    дерево -> длина_массива = 0;
    дерево -> всего_узл = 0;
    вернуть 0; 	// без ошибок
    }
	иначе
    вернуть -1;	//память не была выделена ранее	
	
}
//==========================================================
// Функция добавляет новый токен в конец массива без
//  привязки к дереву
//==========================================================
цел АСДдобавить_токен(ТАСД *дерево, цел тип_токена, симв16 *лексема, б64 длина_лексемы)
{
	если (дерево -> длина_массива == дерево -> всего_токенов)
	{
	  // выделяем дополнительную память
	  дерево -> длина_массива += 20000L;
	  Тузел* врем = NULL;
	  врем = (Тузел*)realloc(дерево-> узлы, дерево -> длина_массива * sizeof(Тузел)); //добавляем памяти на 20000 узлов
	  если (врем == NULL){
	  	вернуть  сообщение_об_ошибке(ОШИБКА_РАСШИРЕНИЯ_ДЕРЕВА);	//не удалось выделить память
	  	
	  }
	  
	  дерево-> узлы = врем; 
	}
	  дерево -> узлы[дерево -> всего_токенов].тип_узла = тип_токена;
	  дерево -> узлы[дерево -> всего_токенов].длина_лексемы = длина_лексемы;
	  дерево -> узлы[дерево -> всего_токенов].лексема = лексема;
	  дерево -> всего_токенов++;                	// общее количество токенов +1
	
	вернуть 0; 	// без ошибок
}
//==========================================================
// Возращает вид текущего токена
//==========================================================
цел АСДтокен(ТАСД *дерево)
{
	вернуть дерево->узлы[дерево->индекс_токена].тип_узла;
}
//==========================================================
// Возращает вид следующего токена
//==========================================================
цел АСДтокен1(ТАСД *дерево)
{
	если (дерево->индекс_токена+1 < дерево->всего_токенов){
    вернуть дерево->узлы[дерево->индекс_токена+1].тип_узла;
	}
	вернуть КОНЕЦ_ФАЙЛА;
}
//==========================================================
// Возращает вид послеследующего токена
//==========================================================
цел АСДтокен2(ТАСД *дерево)
{
	если (дерево->индекс_токена+2 < дерево->всего_токенов){
    вернуть дерево->узлы[дерево->индекс_токена+2].тип_узла;
	}
	вернуть КОНЕЦ_ФАЙЛА;
}
//==========================================================
// Возращает указатель на лексему. Внимание!! Лексема не имеет 
// завершающего нулевого символа
//==========================================================
подстав симв16* АСДлексема(ТАСД *дерево)
{
	вернуть дерево->узлы[дерево->индекс_токена].лексема;
}
//==========================================================
// Функция для отладки. Печатает токен
//==========================================================
цел АСДраспечатать_токен(ТАСД *дерево)
{
	
	пчтф16 (L"%4i [%s] : \"", 	дерево->индекс_токена, массив_названий [АСДтокен(дерево)]);
	б64 инд;
	симв16 * врем_строка = АСДлексема(дерево);                    	
	для ( инд =0; инд < дерево->узлы[дерево->индекс_токена].длина_лексемы ; инд++ ){
    пчтз16(врем_строка[инд]);
	}
	пчтф16(L"\"\n");
}
//==========================================================
// Функция для отладки. Печатает в столбик все токены
//==========================================================
цел АСДраспечатать_все_токены(ТАСД *дерево)
{
	для ( дерево->индекс_токена = 1; дерево->индекс_токена < дерево->всего_токенов; дерево->индекс_токена++ ){
    АСДраспечатать_токен(дерево);
	}
	пчтф16(L"Всего токенов: %i\n", дерево->всего_токенов-1);//нулевой узел не считаем
}

0

21

Проект в вовсю развивается. Немножко "причешу" код, напишу комментарии и мы взглянем на внутренности нашего лексера. Пару картинок для иллюстрации. Это один и тот же файл, при одинаковом шрифте и фоне.
Без подсветки:
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;padding:0.1em;color:#abb2bf;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
OL {background:#3b312c}
</style></head>
<strong class="legend" >Код:</strong><div class="scrollbox" style="overflow: auto; height: 35em"><pre><code class="code"><ol><li><span class="var">//===========================================================</span>
<li><span class="var">// Файл:    ASTtree.r</span>
<li><span class="var">// Версия:    1.01</span>
<li><span class="var">// Дата:    10:44 07.05.2022</span>
<li><span class="var">// Описание: Определение функций работы с синтаксическим деревом</span>
<li><span class="var">//        и массивом токенов</span>
<li><span class="var">// Автор:</span>
<li><span class="var">//===========================================================</span>
<li><span class="var">#вставка "ASTtree.h"</span>
<li><span class="var">#вставка "token_names.h" </span><span class="var"> </span><span class="var">//таблица строк с наименованиями токенов</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Начальная инициализация AST - дерева</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДподготовить</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="var">NULL</span><span class="var">)</span>
<li><span class="var">    </span><span class="var">дерево</span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">(</span><span class="var">Тузел</span><span class="var">*</span><span class="var">)</span><span class="var"> </span><span class="var">malloc</span><span class="var">(</span><span class="var"> </span><span class="var">10000</span><span class="var"> </span><span class="var">*</span><span class="var"> </span><span class="var">sizeof</span><span class="var">(</span><span class="var">Тузел</span><span class="var">)</span><span class="var"> </span><span class="var">)</span><span class="var">;</span><span class="var"> </span><span class="var">//выделяем память на 10000 узлов</span>
<li><span class="var"> </span><span class="var">иначе</span>
<li><span class="var">    </span><span class="var">вернуть</span><span class="var">  </span><span class="var">сообщение_об_ошибке</span><span class="var">(</span><span class="var">ОШИБКА_СОЗДАНИЯ_ДЕРЕВА</span><span class="var">)</span><span class="var">;</span><span class="var"> </span><span class="var">//память уже выделена ранее </span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">длина_массива</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">10000</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_узл</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">1</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">индекс_узла</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">0</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">1</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">индекс_токена</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">1</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">0</span><span class="var">]</span><span class="var">.</span><span class="var">тип_узла</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">0</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">0</span><span class="var">]</span><span class="var">.</span><span class="var">всего_доч</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">0</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">0</span><span class="var">;</span><span class="var"> </span><span class="var">// без ошибок</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Освобождение памяти AST - дерева</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДосвободить_память</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">//********************************************</span>
<li><span class="var"> </span><span class="var">// Сначала нужно пробежаться по узлам и при </span>
<li><span class="var"> </span><span class="var">// необходимости освободить память дочерние</span>
<li><span class="var"> </span><span class="var">//********************************************</span>
<li><span class="var"> </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var"> </span><span class="var">!=</span><span class="var"> </span><span class="var">NULL</span><span class="var">)</span><span class="var">{</span>
<li><span class="var">    </span><span class="var">free</span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var">)</span><span class="var">;</span><span class="var"> </span><span class="var">//освобождаем память</span>
<li><span class="var">    </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">NULL</span><span class="var">;</span>
<li><span class="var">    </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">длина_массива</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">0</span><span class="var">;</span>
<li><span class="var">    </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_узл</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">0</span><span class="var">;</span>
<li><span class="var">    </span><span class="var">вернуть</span><span class="var"> </span><span class="var">0</span><span class="var">;</span><span class="var"> </span><span class="var">// без ошибок</span>
<li><span class="var">    </span><span class="var">}</span>
<li><span class="var"> </span><span class="var">иначе</span>
<li><span class="var">    </span><span class="var">вернуть</span><span class="var"> </span><span class="var">-</span><span class="var">1</span><span class="var">;</span><span class="var"> </span><span class="var">//память не была выделена ранее </span>
<li><span class="var"> </span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Функция добавляет новый токен в конец массива без</span>
<li><span class="var">//  привязки к дереву</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДдобавить_токен</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">,</span><span class="var"> </span><span class="var">цел</span><span class="var"> </span><span class="var">тип_токена</span><span class="var">,</span><span class="var"> </span><span class="var">симв16</span><span class="var"> </span><span class="var">*</span><span class="var">лексема</span><span class="var">,</span><span class="var"> </span><span class="var">б64</span><span class="var"> </span><span class="var">длина_лексемы</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">длина_массива</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var">)</span>
<li><span class="var"> </span><span class="var">{</span>
<li><span class="var">   </span><span class="var">// выделяем дополнительную память</span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">длина_массива</span><span class="var"> </span><span class="var">+=</span><span class="var"> </span><span class="var">20000</span><span class="var">;</span>
<li><span class="var">   </span><span class="var">Тузел</span><span class="var">*</span><span class="var"> </span><span class="var">врем</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">NULL</span><span class="var">;</span>
<li><span class="var">   </span><span class="var">врем</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">(</span><span class="var">Тузел</span><span class="var">*</span><span class="var">)</span><span class="var">realloc</span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var">,</span><span class="var"> </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">длина_массива</span><span class="var"> </span><span class="var">*</span><span class="var"> </span><span class="var">sizeof</span><span class="var">(</span><span class="var">Тузел</span><span class="var">)</span><span class="var">)</span><span class="var">;</span><span class="var"> </span><span class="var">//добавляем памяти на 20000 узлов</span>
<li><span class="var">   </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">врем</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="var">NULL</span><span class="var">)</span><span class="var">{</span>
<li><span class="var">   </span><span class="var">вернуть</span><span class="var">  </span><span class="var">сообщение_об_ошибке</span><span class="var">(</span><span class="var">ОШИБКА_РАСШИРЕНИЯ_ДЕРЕВА</span><span class="var">)</span><span class="var">;</span><span class="var"> </span><span class="var">//не удалось выделить память</span>
<li><span class="var">   </span>
<li><span class="var">   </span><span class="var">}</span>
<li><span class="var">   </span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">врем</span><span class="var">;</span><span class="var"> </span>
<li><span class="var"> </span><span class="var">}</span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var">]</span><span class="var">.</span><span class="var">тип_узла</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">тип_токена</span><span class="var">;</span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var">]</span><span class="var">.</span><span class="var">длина_лексемы</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">длина_лексемы</span><span class="var">;</span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var">]</span><span class="var">.</span><span class="var">лексема</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">лексема</span><span class="var">;</span>
<li><span class="var">   </span><span class="var">дерево</span><span class="var"> </span><span class="var">-></span><span class="var"> </span><span class="var">всего_токенов</span><span class="var">++</span><span class="var">;</span><span class="var">                </span><span class="var">// общее количество токенов +1</span>
<li><span class="var"> </span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">0</span><span class="var">;</span><span class="var"> </span><span class="var">// без ошибок</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Возращает вид текущего токена</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДтокен</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">]</span><span class="var">.</span><span class="var">тип_узла</span><span class="var">;</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Возращает вид следующего токена</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДтокен1</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">+</span><span class="var">1</span><span class="var"> </span>&lt;<span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">всего_токенов</span><span class="var">)</span><span class="var">{</span>
<li><span class="var">    </span><span class="var">вернуть</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">+</span><span class="var">1</span><span class="var">]</span><span class="var">.</span><span class="var">тип_узла</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">}</span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">КОНЕЦ_ФАЙЛА</span><span class="var">;</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Возращает вид послеследующего токена</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">цел</span><span class="var"> </span><span class="var">АСДтокен2</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">если</span><span class="var"> </span><span class="var">(</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">+</span><span class="var">2</span><span class="var"> </span>&lt;<span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">всего_токенов</span><span class="var">)</span><span class="var">{</span>
<li><span class="var">    </span><span class="var">вернуть</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">+</span><span class="var">2</span><span class="var">]</span><span class="var">.</span><span class="var">тип_узла</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">}</span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">КОНЕЦ_ФАЙЛА</span><span class="var">;</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Возращает указатель на лексему. Внимание!! Лексема не имеет </span>
<li><span class="var">// завершающего нулевого символа</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">симв16</span><span class="var">*</span><span class="var"> </span><span class="var">АСДлексема</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">вернуть</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">]</span><span class="var">.</span><span class="var">лексема</span><span class="var">;</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Функция для отладки. Печатает токен</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">пуст</span><span class="var"> </span><span class="var">АСДраспечатать_токен</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span>
<li><span class="var"> </span><span class="var">пчтф16</span><span class="var"> </span><span class="var">(</span><span class="var">L"%4i [%s] : \""</span><span class="var">,</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">,</span><span class="var"> </span><span class="var">массив_названий</span><span class="var"> </span><span class="var">[</span><span class="var">АСДтокен</span><span class="var">(</span><span class="var">дерево</span><span class="var">)</span><span class="var">]</span><span class="var">)</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">б64</span><span class="var"> </span><span class="var">инд</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">симв16</span><span class="var"> </span><span class="var">*</span><span class="var"> </span><span class="var">врем_строка</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">АСДлексема</span><span class="var">(</span><span class="var">дерево</span><span class="var">)</span><span class="var">;</span><span class="var">                    </span>
<li><span class="var"> </span><span class="var">для</span><span class="var"> </span><span class="var">(</span><span class="var"> </span><span class="var">инд</span><span class="var"> </span><span class="var">=</span><span class="var">0</span><span class="var">;</span><span class="var"> </span><span class="var">инд</span><span class="var"> </span>&lt;<span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">узлы</span><span class="var">[</span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">]</span><span class="var">.</span><span class="var">длина_лексемы</span><span class="var"> </span><span class="var">;</span><span class="var"> </span><span class="var">инд</span><span class="var">++</span><span class="var"> </span><span class="var">)</span><span class="var">{</span>
<li><span class="var">    </span><span class="var">пчтз16</span><span class="var">(</span><span class="var">врем_строка</span><span class="var">[</span><span class="var">инд</span><span class="var">]</span><span class="var">)</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">}</span>
<li><span class="var"> </span><span class="var">пчтф16</span><span class="var">(</span><span class="var">L"\"\n"</span><span class="var">)</span><span class="var">;</span>
<li><span class="var">}</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">// Функция для отладки. Печатает в столбик все токены</span>
<li><span class="var">//==========================================================</span>
<li><span class="var">пуст</span><span class="var"> </span><span class="var">АСДраспечатать_все_токены</span><span class="var">(</span><span class="var">ТАСД</span><span class="var"> </span><span class="var">*</span><span class="var">дерево</span><span class="var">)</span>
<li><span class="var">{</span>
<li><span class="var"> </span><span class="var">для</span><span class="var"> </span><span class="var">(</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var"> </span><span class="var">=</span><span class="var"> </span><span class="var">1</span><span class="var">;</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var"> </span>&lt;<span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">всего_токенов</span><span class="var">;</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">индекс_токена</span><span class="var">++</span><span class="var"> </span><span class="var">)</span><span class="var">{</span>
<li><span class="var">    </span><span class="var">АСДраспечатать_токен</span><span class="var">(</span><span class="var">дерево</span><span class="var">)</span><span class="var">;</span>
<li><span class="var"> </span><span class="var">}</span>
<li><span class="var"> </span><span class="var">пчтф16</span><span class="var">(</span><span class="var">L"Всего токенов: %i\n"</span><span class="var">,</span><span class="var"> </span><span class="var">дерево</span><span class="var">-></span><span class="var">всего_токенов</span><span class="var">-</span><span class="var">1</span><span class="var">)</span><span class="var">;</span><span class="var">//нулевой узел не считаем</span>
<li><span class="var">}</span>
<li></ol></code></pre></div>[/html]
С подсветкой:
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c;color:#abb2bf}
</style></head>
<div class="code-box"><strong class="legend" >Код:</strong><div class="blockcode"><div class="scrollbox" style="overflow: auto; height: 40em"><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   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
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="coments">//===========================================================</span>
<span class="coments">// Файл:    ASTtree.r</span>
<span class="coments">// Версия:    1.01</span>
<span class="coments">// Дата:    10:44 07.05.2022</span>
<span class="coments">// Описание: Определение функций работы с синтаксическим деревом</span>
<span class="coments">//        и массивом токенов</span>
<span class="coments">// Автор:</span>
<span class="coments">//===========================================================</span>
<span class="macro">#вставка "ASTtree.h"</span>
<span class="macro">#вставка "token_names.h"    //таблица строк с наименованиями токенов</span>
<span class="coments">//==========================================================</span>
<span class="coments">// Начальная инициализация AST - дерева</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДподготовить</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">дерево</span>-><span class="ident">узлы</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="ident">NULL</span><span class="del1">)</span>
<span class="var">    </span><span class="ident">дерево</span>-><span class="var"> </span><span class="ident">узлы</span><span class="var"> </span>=<span class="var"> </span><span class="del1">(</span><span class="ident">Тузел</span>*<span class="del1">)</span><span class="var"> </span><span class="funct">malloc</span><span class="del1">(</span><span class="var"> </span><span class="digit">10000</span><span class="ident">L</span><span class="var"> </span>*<span class="var"> </span><span class="oper">sizeof</span><span class="del1">(</span><span class="ident">Тузел</span><span class="del1">)</span><span class="var"> </span><span class="del1">)</span>;<span class="var"> </span><span class="coments">//выделяем память на 10000 узлов</span>
<span class="var"> </span><span class="oper">иначе</span>
<span class="var">    </span><span class="oper">вернуть</span><span class="var">  </span><span class="funct">сообщение_об_ошибке</span><span class="del1">(</span><span class="ident">ОШИБКА_СОЗДАНИЯ_ДЕРЕВА</span><span class="del1">)</span>;<span class="var"> </span><span class="coments">//память уже выделена ранее </span>
<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">длина_массива</span><span class="var"> </span>=<span class="var"> </span><span class="digit">10000</span><span class="ident">L</span>;
<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_узл</span><span class="var"> </span>=<span class="var"> </span><span class="digit">1</span>;
<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">индекс_узла</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span><span class="var"> </span>=<span class="var"> </span><span class="digit">1</span>;
<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">индекс_токена</span><span class="var"> </span>=<span class="var"> </span><span class="digit">1</span>;
<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="digit">0</span>].<span class="ident">тип_узла</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="digit">0</span>].<span class="ident">всего_доч</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="digit">0</span>;<span class="var"> </span><span class="coments">// без ошибок</span>
}
<span class="coments">//==========================================================</span>
<span class="coments">// Освобождение памяти AST - дерева</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДосвободить_память</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="coments">//********************************************</span>
<span class="var"> </span><span class="coments">// Сначала нужно пробежаться по узлам и при </span>
<span class="var"> </span><span class="coments">// необходимости освободить память дочерние</span>
<span class="var"> </span><span class="coments">//********************************************</span>
<span class="var"> </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">дерево</span>-><span class="ident">узлы</span><span class="var"> </span>!=<span class="var"> </span><span class="ident">NULL</span><span class="del1">)</span>{
<span class="var">    </span><span class="funct">free</span><span class="del1">(</span><span class="ident">дерево</span>-><span class="var"> </span><span class="ident">узлы</span><span class="del1">)</span>;<span class="var"> </span><span class="coments">//освобождаем память</span>
<span class="var">    </span><span class="ident">дерево</span>-><span class="ident">узлы</span><span class="var"> </span>=<span class="var"> </span><span class="ident">NULL</span>;
<span class="var">    </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">длина_массива</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var">    </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_узл</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var">    </span><span class="oper">вернуть</span><span class="var"> </span><span class="digit">0</span>;<span class="var"> </span><span class="coments">// без ошибок</span>
<span class="var">    </span>}
<span class="var"> </span><span class="oper">иначе</span>
<span class="var">    </span><span class="oper">вернуть</span><span class="var"> </span>-<span class="digit">1</span>;<span class="var"> </span><span class="coments">//память не была выделена ранее </span>
<span class="var"> </span>
}
<span class="coments">//==========================================================</span>
<span class="coments">// Функция добавляет новый токен в конец массива без</span>
<span class="coments">//  привязки к дереву</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДдобавить_токен</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span>,<span class="var"> </span>цел<span class="var"> </span><span class="ident">тип_токена</span>,<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>*<span class="ident">лексема</span>,<span class="var"> </span><span class="ident">б64</span><span class="var"> </span><span class="ident">длина_лексемы</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">длина_массива</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span>+<span class="digit">1</span><span class="del1">)</span>
<span class="var"> </span>{
<span class="var">   </span><span class="coments">// выделяем дополнительную память</span>
<span class="var">   </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">длина_массива</span><span class="var"> </span>+=<span class="var"> </span><span class="digit">20000</span><span class="ident">L</span>;
<span class="var">   </span><span class="ident">Тузел</span>*<span class="var"> </span><span class="ident">врем</span><span class="var"> </span>=<span class="var"> </span><span class="ident">NULL</span>;
<span class="var">   </span><span class="ident">врем</span><span class="var"> </span>=<span class="var"> </span><span class="del1">(</span><span class="ident">Тузел</span>*<span class="del1">)</span><span class="funct">realloc</span><span class="del1">(</span><span class="ident">дерево</span>-><span class="var"> </span><span class="ident">узлы</span>,<span class="var"> </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">длина_массива</span><span class="var"> </span>*<span class="var"> </span><span class="oper">sizeof</span><span class="del1">(</span><span class="ident">Тузел</span><span class="del1">)</span><span class="del1">)</span>;<span class="var"> </span><span class="coments">//добавляем памяти на 20000 узлов</span>
<span class="var">   </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">врем</span><span class="var"> </span><span class="var">==</span><span class="var"> </span><span class="ident">NULL</span><span class="del1">)</span>{
<span class="var">   </span><span class="oper">вернуть</span><span class="var">  </span><span class="funct">сообщение_об_ошибке</span><span class="del1">(</span><span class="ident">ОШИБКА_РАСШИРЕНИЯ_ДЕРЕВА</span><span class="del1">)</span>;<span class="var"> </span><span class="coments">//не удалось выделить память</span>
<span class="var">   </span>
<span class="var">   </span>}
<span class="var">   </span>
<span class="var">   </span><span class="ident">дерево</span>-><span class="var"> </span><span class="ident">узлы</span><span class="var"> </span>=<span class="var"> </span><span class="ident">врем</span>;<span class="var"> </span>
<span class="var"> </span>}
<span class="var">   </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">узлы</span>[<span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span>].<span class="ident">тип_узла</span><span class="var"> </span>=<span class="var"> </span><span class="ident">тип_токена</span>;
<span class="var">   </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">узлы</span>[<span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span>].<span class="ident">длина_лексемы</span><span class="var"> </span>=<span class="var"> </span><span class="ident">длина_лексемы</span>;
<span class="var">   </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">узлы</span>[<span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span>].<span class="ident">лексема</span><span class="var"> </span>=<span class="var"> </span><span class="ident">лексема</span>;
<span class="var">   </span><span class="ident">дерево</span><span class="var"> </span>-><span class="var"> </span><span class="ident">всего_токенов</span>++;<span class="var">                </span><span class="coments">// общее количество токенов +1</span>
<span class="var"> </span>
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="digit">0</span>;<span class="var"> </span><span class="coments">// без ошибок</span>
}
<span class="coments">//==========================================================</span>
<span class="coments">// Возращает вид текущего токена</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДтокен</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="ident">дерево</span>-><span class="ident">индекс_токена</span>].<span class="ident">тип_узла</span>;
}
<span class="coments">//==========================================================</span>
<span class="coments">// Возращает вид следующего токена</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДтокен1</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span>+<span class="digit">1</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">всего_токенов</span><span class="del1">)</span>{
<span class="var">    </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="ident">дерево</span>-><span class="ident">индекс_токена</span>+<span class="digit">1</span>].<span class="ident">тип_узла</span>;
<span class="var"> </span>}
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">КОНЕЦ_ФАЙЛА</span>;
}
<span class="coments">//==========================================================</span>
<span class="coments">// Возращает вид послеследующего токена</span>
<span class="coments">//==========================================================</span>
цел<span class="var"> </span><span class="funct">АСДтокен2</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span>+<span class="digit">2</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">всего_токенов</span><span class="del1">)</span>{
<span class="var">    </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="ident">дерево</span>-><span class="ident">индекс_токена</span>+<span class="digit">2</span>].<span class="ident">тип_узла</span>;
<span class="var"> </span>}
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">КОНЕЦ_ФАЙЛА</span>;
}
<span class="coments">//==========================================================</span>
<span class="coments">// Возращает указатель на лексему. Внимание!! Лексема не имеет </span>
<span class="coments">// завершающего нулевого символа</span>
<span class="coments">//==========================================================</span>
<span class="ident">симв16</span>*<span class="var"> </span><span class="funct">АСДлексема</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="ident">дерево</span>-><span class="ident">индекс_токена</span>].<span class="ident">лексема</span>;
}
<span class="coments">//==========================================================</span>
<span class="coments">// Функция для отладки. Печатает токен</span>
<span class="coments">//==========================================================</span>
пуст<span class="var"> </span><span class="funct">АСДраспечатать_токен</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span>
<span class="var"> </span><span class="funct">пчтф16</span><span class="var"> </span><span class="del1">(</span><span class="str">L&quot;%4i [%s] : \"&quot;</span>,<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span>,<span class="var"> </span><span class="ident">массив_названий</span><span class="var"> </span>[<span class="funct">АСДтокен</span><span class="del1">(</span><span class="ident">дерево</span><span class="del1">)</span>]<span class="del1">)</span>;
<span class="var"> </span><span class="ident">б64</span><span class="var"> </span><span class="ident">инд</span>;
<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>*<span class="var"> </span><span class="ident">врем_строка</span><span class="var"> </span>=<span class="var"> </span><span class="funct">АСДлексема</span><span class="del1">(</span><span class="ident">дерево</span><span class="del1">)</span>;<span class="var">                    </span>
<span class="var"> </span><span class="oper">для</span><span class="var"> </span><span class="del1">(</span><span class="var"> </span><span class="ident">инд</span><span class="var"> </span>=<span class="digit">0</span>;<span class="var"> </span><span class="ident">инд</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">узлы</span>[<span class="ident">дерево</span>-><span class="ident">индекс_токена</span>].<span class="ident">длина_лексемы</span><span class="var"> </span>;<span class="var"> </span><span class="ident">инд</span>++<span class="var"> </span><span class="del1">)</span>{
<span class="var">    </span><span class="funct">пчтз16</span><span class="del1">(</span><span class="ident">врем_строка</span>[<span class="ident">инд</span>]<span class="del1">)</span>;
<span class="var"> </span>}
<span class="var"> </span><span class="funct">пчтф16</span><span class="del1">(</span><span class="str">L&quot;\"\n&quot;</span><span class="del1">)</span>;
}
<span class="coments">//==========================================================</span>
<span class="coments">// Функция для отладки. Печатает в столбик все токены</span>
<span class="coments">//==========================================================</span>
пуст<span class="var"> </span><span class="funct">АСДраспечатать_все_токены</span><span class="del1">(</span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{
<span class="var"> </span><span class="oper">для</span><span class="var"> </span><span class="del1">(</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span><span class="var"> </span>=<span class="var"> </span><span class="digit">1</span>;<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="ident">дерево</span>-><span class="ident">всего_токенов</span>;<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">индекс_токена</span>++<span class="var"> </span><span class="del1">)</span>{
<span class="var">    </span><span class="funct">АСДраспечатать_токен</span><span class="del1">(</span><span class="ident">дерево</span><span class="del1">)</span>;
<span class="var"> </span>}
<span class="var"> </span><span class="funct">пчтф16</span><span class="del1">(</span><span class="str">L&quot;Всего токенов: %i\n&quot;</span>,<span class="var"> </span><span class="ident">дерево</span>-><span class="ident">всего_токенов</span>-<span class="digit">1</span><span class="del1">)</span>;<span class="coments">//нулевой узел не считаем</span>
}</pre></td></tr></table></div></div></div>[/html]

Отредактировано Евгений (2022-05-11 22:24:26)

0

22

В html я не знаю почти ничего, поэтому наверняка есть какие-то ошибки. По идее должна была быть нумерация строк... Но сейчас она пропала, хотя при проверке локальной странички все работает. Если кто заметит некорректную работу, прошу сообщить.

0

23

[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c;color:#abb2bf}
</style></head>
<div class="code-box"><strong class="legend" >Код:</strong><div class="blockcode"><div class="scrollbox" style="overflow: auto; height: 40em"><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   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
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="coments">//=========================================================================</span>
<span class="coments">// Основная функция, осуществляет лексичекий анализ</span>
<span class="coments">// на входе ТБуфер *буф, результаты в ТАСД *дерево</span>
<span class="coments">//=========================================================================</span>
цел<span class="var"> </span><span class="funct">лексер</span><span class="var"> </span><span class="del1">(</span><span class="ident">ТБуфер</span><span class="var"> </span>*<span class="ident">буф</span>,<span class="var"> </span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>
{<span class="var"> </span>
<span class="var"> </span><span class="coments">//выделение памяти под массив токенов и начальная инициализация</span>
<span class="var"> </span><span class="funct">АСДподготовить</span><span class="del1">(</span><span class="ident">дерево</span><span class="del1">)</span>;<span class="var"> </span>
<span class="var"> </span>
<span class="var"> </span><span class="oper">для</span><span class="var"> </span><span class="del1">(</span><span class="var"> </span>;<span class="var"> </span><span class="ident">буф</span><span class="var"> </span>-><span class="var"> </span><span class="ident">текст16</span>[<span class="ident">буф</span><span class="var"> </span>-><span class="var"> </span><span class="ident">индекс</span>]<span class="var"> </span>!=<span class="var"> </span><span class="str">'\0'</span>;<span class="var"> </span><span class="del1">)</span><span class="var"> </span>{
<span class="var">    </span><span class="coments">// разбираем последовательность</span>
<span class="var">    </span><span class="coments">//если функция возвращает 1 - значит успешно, начинаем цикл заново</span>
<span class="var">    </span><span class="coments">//если             0 - значит условие не соблюдено, продолжаем цикл</span>
<span class="var">    </span><span class="coments">//если             >1 - значит ошибка</span>
<span class="var">    </span>
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_пробельный_символ</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_директивы_препроцессора</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_число</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span>
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_строку</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">        </span>
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_идентификатор</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_коментарии</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span>
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_скобки</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span>
<span class="var">    </span><span class="oper">если</span><span class="del1">(</span><span class="var"> </span><span class="digit">0</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="funct">сканировать_операции</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span><span class="del1">)</span>{
<span class="var">        </span><span class="oper">заново</span>;<span class="coments">// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала</span>
<span class="var">    </span>}
<span class="var">    </span><span class="coments">//если дошли до этого места, значит ошибочный символ</span>
<span class="var">    </span><span class="funct">обработать_неизвестный_символ</span><span class="del1">(</span><span class="ident">буф</span>,<span class="var"> </span><span class="ident">дерево</span><span class="del1">)</span>;
<span class="var">    </span><span class="oper">заново</span>;<span class="var">    </span>
<span class="var">    </span>
<span class="var"> </span>}
<span class="var"> </span><span class="coments">//Завершили сканирование.Добавляем последний токен КОНЕЦ_ФАЙЛА</span>
<span class="var"> </span><span class="funct">АСДдобавить_токен</span><span class="del1">(</span><span class="ident">дерево</span>,<span class="var"> </span><span class="ident">КОНЕЦ_ФАЙЛА</span>,<span class="var"> </span><span class="del2">&amp;</span><span class="ident">буф</span><span class="var"> </span>-><span class="var"> </span><span class="ident">текст16</span><span class="var"> </span>[<span class="ident">буф</span><span class="var"> </span>-><span class="var"> </span><span class="ident">индекс</span>],<span class="var"> </span><span class="digit">1</span><span class="del1">)</span>;
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="digit">0</span>;
}</pre></td></tr></table></div></div></div>[/html]

Отредактировано Евгений (2022-05-11 22:25:56)

0

24

Разбирать каждую функцию, входящую в состав лексера не будем. Там все очевидно, хотя и объемно. Единственно, о чем стоит сказать, так это о функции, сканирующей идентификаторы. При распознавании очередного идентификатора осуществляется попытка поиска соответствия в словаре ключевых слов. Словарь и бинарный поиск в нем сделаны примитивно, без всяких хэш-таблиц. По традиции два файла: с объявлениями и реализацией лексического анализатора.
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#abb2bf;font-family:'Courier New'; font-size:12pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c}
</style></head>
<strong class="legend" >Код:</strong><div class="scrollbox" style="overflow: auto; height: 35em; border:#2b211c;border-width:.1em .1em .1em .8em;padding:.2em .6em; "><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="macro">#если_нет LEXER_H</span>
<span class="macro">#макрос   LEXER_H </span>
<span class="coments">//===========================================================</span>
<span class="coments">// Файл:    lexer.rh</span>
<span class="coments">// Версия:</span>
<span class="coments">// Дата:    9:06 08.05.2022</span>
<span class="coments">// Описание: Объявление основных фукций лексического анализатор</span>
<span class="coments">// Автор:</span>
<span class="coments">//===========================================================</span>
<span class="macro">#вставка    "textbuffer.h"</span>
<span class="macro">#вставка    "stack.h"</span>
<span class="coments">//===========================================================</span>
<span class="coments">// Основная функция лексического анализа кода</span>
<span class="coments">//===========================================================</span>
<span class="del2">цел</span><span class="var"> </span><span class="funct">лексер</span><span class="var"> </span><span class="del1">(</span><span class="del1">)</span><span class="del2">;</span>

<span class="macro">#к_если    //LEXER_H</span>
<span class="var">  </span></pre></td></tr></table></div>[/html]

Отредактировано Евгений (2022-05-11 20:07:22)

0

25

Код лексера пока без подсветки. Генератор html пока работает некорректно

0

26

Возник один нюанс... Подсветка отлично работает, только html-текст "раздувается" относительно исходного в 4-5 раз. А размер одного сообщения ограничен 64КБ. Поэтому файл лексера будет без подсветки.

Код:
//===========================================================
// 	Файл:    lexer.r
// 	Версия:    1.01
// 	Дата:    22:27 07.05.2022
//	Описание:	  Лексический анализатор (лексер)
//        Лексический анализатор пытается распознать в тексте элементы языка С/С++
//        в русифицированном и оригинальном вариантах и формирует массив токенов.
//        Массив токенов находится внутри переменной 'дерево' типа 'ТАСД'
//        Добавление токена осуществляется с помощью функции: 
//        цел АСДдобавить_токен(ТАСД *дерево, цел тип_токена, симв16 *лексема, б64 длина_лексемы) 
//          
//          Распознанные комментарии и пробельные последовательности также являются 
//        соответствующими токенами. При появлении "запрещенного" символа или
//        возникновении ошибки распознавания такой символ помещается
//        в токен НЕИЗВЕСТНЫЙ_СИМВОЛ и лексер продожает попытку работы со 
//        следующего символа.
//        Полный перечень токенов находится в файле tokens.rh 
//	Автор:
//===========================================================
#вставка	"textbuffer.h"
#вставка	"ASTtree.h"
#вставка    "stack.h"
#вставка    "slovar.h"
#вставка    "keywords.h"

#макрос    ЭТО_ЦИФРА(х) (0x30 <= (х) && (х) <= 0x39)
#макрос    ЭТО_ПРОБЕЛЬНЫЙ_СИМВОЛ(х) ((х) == 16"20 || (х) == 16"09)
#макрос    ЭТО_СИМВОЛ_КОНЦА_СТРОКИ(х) ((х) == 16"0D || (х) == 16"0A  || (х) == '\0')
#макрос    ЭТО_АРИФМЕТИЧЕСКИЙ_СИМВОЛ(х) ( (х) == 16"25 || (х) == 16"2A || (х) == 16"2B || (х) == 16"2D || (х) == 16"2F )
#макрос    ЭТО_СИМВОЛ_СРАВНЕНИЯ(х) ( ( 0x3C <= (х) && (х) <= 0x3E) || (х) == 16"21 || (х) == 16"26 || (х) == 16"5E || (х) == 16"7E)

#макрос    ЭТО_СКОБКИ(х)  ( (х) == 16"28 || (х) == 16"29 || (х) == 16"5B || (х) == 16"5D || (х) == 16"7B || (х) == 16"7D )
#макрос    ЭТО_ПУНКТУАЦИЯ(х)  ( (х) == 16"2C || (х) == 16"2E || (х) == 16"3B || (х) == 16"3A )

#макрос    ЭТО_ЛАТИНИЦА(х) ((16"41 <= (х) && (х) <= 16"5A) || (16"61 <= (х) && (х) <= 16"7A))
#макрос    ЭТО_КИРИЛЛИЦА(х) ((16"0410 <= (х) && (х) <= 16"044F) || (х) == 16"401 || (х) == 16"451)
#макрос    ЭТО_НЕПРОБЕЛЬНЫЙ_РАЗДЕЛИТЕЛЬ(х) (ЭТО_СИМВОЛ_КОНЦА_СТРОКИ(х) || ЭТО_АРИФМЕТИЧЕСКИЙ_СИМВОЛ(х)|| ЭТО_СИМВОЛ_СРАВНЕНИЯ(х)  || ЭТО_СКОБКИ(х) || ЭТО_ПУНКТУАЦИЯ(х))
#макрос    ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ(х) (ЭТО_ПРОБЕЛЬНЫЙ_СИМВОЛ(х) || ЭТО_СИМВОЛ_КОНЦА_СТРОКИ(х) ||ЭТО_АРИФМЕТИЧЕСКИЙ_СИМВОЛ(х)|| ЭТО_СИМВОЛ_СРАВНЕНИЯ(х)  || ЭТО_СКОБКИ(х) || ЭТО_ПУНКТУАЦИЯ(х))

#макрос    КРУГЛАЯ_СКОБКА 1
#макрос    КВАДРАТНАЯ_СКОБКА 2
#макрос    ФИГУРНАЯ_СКОБКА 3
//===========================================================================
// В словаре лежат ключевые слова. Проверяем является ли идентификатор
// ключевым словом и каким именно
// список_ключевых_слов, значения_ключевых_слов лежат в файле keywords.rh
//===========================================================================
ТСловарь словарь_ключевых_слов =
{ 
	список_ключевых_слов, значения_ключевых_слов,0,0,0,0,114
};

цел сканировать_коментарии(ТБуфер *буф, ТАСД *дерево);

//===========================================================================
// Функция обрабатывает пробельные символы
//===========================================================================
цел сканировать_пробельный_символ(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема;
	б64 начальный_индекс = буф -> индекс;
	//сканируем пробелы и табуляцию
	если (ЭТО_ПРОБЕЛЬНЫЙ_СИМВОЛ(буф -> текст16 [буф -> индекс]) ){
    лексема = &(буф -> текст16 [буф -> индекс]);
    буф -> индекс++;
    пока( ЭТО_ПРОБЕЛЬНЫЙ_СИМВОЛ(буф -> текст16 [буф -> индекс]) ){
    	буф -> индекс++;
    }
    АСДдобавить_токен(дерево, ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ, лексема, буф -> индекс - начальный_индекс);
    вернуть 1;
	}
	//сканируем конец строки
	если ( буф -> текст16 [буф -> индекс] == 16"0D  && 	буф -> текст16 [буф -> индекс+1]  == 16"0A){
    лексема = &(буф -> текст16 [буф -> индекс]);
    буф -> индекс++;
    буф -> индекс++;
    АСДдобавить_токен(дерево, ПЕРЕВОД_СТРОКИ, лексема, 2);
    вернуть 1;
	}
	//если конец файла. Скорее всего  избыточно
	если (буф -> текст16 [буф -> индекс] == '\0'){
    АСДдобавить_токен(дерево, КОНЕЦ_ФАЙЛА, лексема, буф -> индекс - начальный_индекс);
    вернуть 1;
	}	
	вернуть 0;	
}
//===========================================================================
// Функция распознает директивы препроцессора
//===========================================================================
цел сканировать_директивы_препроцессора(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема;
	б64 начальный_индекс = буф -> индекс;
	//сканируем директивы препроцессора
	если (буф -> текст16 [буф -> индекс] == '#' ){
    лексема = &(буф -> текст16 [буф -> индекс]);
    буф -> индекс++;
    пока( (буф -> текст16 [буф -> индекс] != 16"0D  && 	буф -> текст16 [буф -> индекс+1]  != 16"0A)
    	&& буф -> текст16 [буф -> индекс] != '\0'){
    	//Возможен вариант многострочного макроса с символом '\' в качестве продолжения
    	если(буф -> индекс > буф -> длина_текста16-2)
    	если (буф -> текст16 [буф -> индекс] == '\\' && буф -> текст16 [буф -> индекс+1] == 16"0D  && 	буф -> текст16 [буф -> индекс+2]  == 16"0A){
        //завершаем первую часть директивы препроцессора
        буф -> индекс++;
        АСДдобавить_токен(дерево, ДИРЕКТИВА_ПРЕПРОЦЕССОРА, лексема, буф -> индекс - начальный_индекс);
        //сканируем конец строки
        если ( буф -> текст16 [буф -> индекс] == 16"0D  && 	буф -> текст16 [буф -> индекс+1]  == 16"0A){
        //	сканировать_пробельный_символ(буф, дерево);
        //формируем токен перевод строки
        	лексема = &(буф -> текст16 [буф -> индекс]);
        	буф -> индекс += 2;
        	АСДдобавить_токен(дерево, ПЕРЕВОД_СТРОКИ, лексема, 2);
        	
        	лексема = &(буф -> текст16 [буф -> индекс]);
        	начальный_индекс = буф -> индекс;
        }
        иначе{
        	//после символа '\'должен идти перевод строки
        	//если нет, то выходим с ошибкой
        	вернуть 2;
        }
    	}	
    	буф -> индекс++;
    }
    АСДдобавить_токен(дерево, ДИРЕКТИВА_ПРЕПРОЦЕССОРА, лексема, буф -> индекс - начальный_индекс);
    вернуть 1;
	}
	
	вернуть 0;	
}

//===========================================================================
// Функция распознает целые числа в десятичном, двоичном, шеснадцатиричном
// виде и числа с плавающей точкой.
// Функция в настоящий момент не обрабатывает суффиксы чисел (u,U,l,L,f,F,h,H)
//===========================================================================
//#макрос    ПРЕФИКС_ДВОИЧНОГО_ЧИСЛА(х) ((х) == '2' && (х) == 16"22 || (х) == '0' && (х) == 'b')
цел сканировать_число(ТБуфер *буф, ТАСД *дерево)
{
	если(ЭТО_ЦИФРА(буф -> текст16 [буф -> индекс]))
    ;
	иначе
    вернуть 0;
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	б64 начальный_индекс = буф -> индекс;
	//если префикс двоичного числа 2" или 0b
	если(((буф -> текст16 [буф -> индекс] == '2') && (буф -> текст16 [буф -> индекс+1] == 16"22))
    || ((буф -> текст16 [буф -> индекс] == '0') && (буф -> текст16 [буф -> индекс+1] == 'b')))
	{
    буф -> индекс++;
    буф -> индекс++;
    для (;;)
    {
    	если(буф -> текст16 [буф -> индекс] == '0' || буф -> текст16 [буф -> индекс] == '1' || буф -> текст16 [буф -> индекс] == '_'){
        буф -> индекс++;
    	}
    	иначе если (ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ(буф -> текст16 [буф -> индекс])){
        // Успешный разбор двоичного числа
        АСДдобавить_токен(дерево, ДВОИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть 1;
    	}
    	иначе {
        //ошибка_в_символе(буф -> индекс);
        АСДдобавить_токен(дерево, ДВОИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    	}
    }
	}
	//если префикс шестнадцатеричного числа 16"
	если(буф -> текст16 [буф -> индекс] == '1' && буф -> текст16 [буф -> индекс+1] == '6' 
    	&& буф -> текст16 [буф -> индекс+2] == 16"22)
	{
    буф -> индекс++;
    буф -> индекс++;
    буф -> индекс++;
    для (;;)
    {
    	если(ЭТО_ЦИФРА( буф -> текст16 [буф -> индекс] ) 
    	|| буф -> текст16 [буф -> индекс] == 16"0410 //'А'
    	|| буф -> текст16 [буф -> индекс] == 16"0411 //'Б'
    	|| буф -> текст16 [буф -> индекс] == 16"0426 //'Ц'
    	|| буф -> текст16 [буф -> индекс] == 16"0414 //'Д'
    	|| буф -> текст16 [буф -> индекс] == 16"0415 //'Е'
    	|| буф -> текст16 [буф -> индекс] == 16"0424 //'Ф'
    	|| буф -> текст16 [буф -> индекс] == 16"0430 //'а'
    	|| буф -> текст16 [буф -> индекс] == 16"0431 //'б'
    	|| буф -> текст16 [буф -> индекс] == 16"0446 //'ц'
    	|| буф -> текст16 [буф -> индекс] == 16"0434 //'д'
    	|| буф -> текст16 [буф -> индекс] == 16"0435 //'е'
    	|| буф -> текст16 [буф -> индекс] == 16"0444 //'ф'
    	|| буф -> текст16 [буф -> индекс] == 'A' //'А'
    	|| буф -> текст16 [буф -> индекс] == 'B' //'Б'
    	|| буф -> текст16 [буф -> индекс] == 'C' //'Ц'
    	|| буф -> текст16 [буф -> индекс] == 'D' //'Д'
    	|| буф -> текст16 [буф -> индекс] == 'E' //'Е'
    	|| буф -> текст16 [буф -> индекс] == 'F' //'Ф'
    	|| буф -> текст16 [буф -> индекс] == 'a' //'а'
    	|| буф -> текст16 [буф -> индекс] == 'b' //'б'
    	|| буф -> текст16 [буф -> индекс] == 'c' //'ц'
    	|| буф -> текст16 [буф -> индекс] == 'd' //'д'
    	|| буф -> текст16 [буф -> индекс] == 'e' //'е'
    	|| буф -> текст16 [буф -> индекс] == 'f' //'ф'|| буф -> текст16 [буф -> индекс] == '_'
    	){
        буф -> индекс++;
    	}
    	иначе 
    	
    	если (ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ(буф -> текст16 [буф -> индекс])){
        // Успешный разбор шестнадцатеричного числа
        АСДдобавить_токен(дерево, ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть 1;
    	}
    	иначе {
        //ошибка_в_символе(буф -> индекс);
        АСДдобавить_токен(дерево, ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    	}
    }
	}
	//если префикс шестнадцатеричного числа 0x
	если( буф -> текст16 [буф -> индекс] == '0' && буф -> текст16 [буф -> индекс+1] == 'x')
	{
    
    буф -> индекс++;
    буф -> индекс++;
    для (;;)
    {
    	буф -> текст16 [буф -> индекс] = буф -> текст16 [буф -> индекс];
    	если(ЭТО_ЦИФРА( буф -> текст16 [буф -> индекс] ) 
    	|| буф -> текст16 [буф -> индекс] == 'A' //'А'
    	|| буф -> текст16 [буф -> индекс] == 'B' //'Б'
    	|| буф -> текст16 [буф -> индекс] == 'C' //'Ц'
    	|| буф -> текст16 [буф -> индекс] == 'D' //'Д'
    	|| буф -> текст16 [буф -> индекс] == 'E' //'Е'
    	|| буф -> текст16 [буф -> индекс] == 'F' //'Ф'
    	|| буф -> текст16 [буф -> индекс] == 'a' //'а'
    	|| буф -> текст16 [буф -> индекс] == 'b' //'б'
    	|| буф -> текст16 [буф -> индекс] == 'c' //'ц'
    	|| буф -> текст16 [буф -> индекс] == 'd' //'д'
    	|| буф -> текст16 [буф -> индекс] == 'e' //'е'
    	|| буф -> текст16 [буф -> индекс] == 'f' //'ф'
    	|| буф -> текст16 [буф -> индекс] == '_'
    	){
        буф -> индекс++;
    	}
    	иначе 
    	
    	если (ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ( буф -> текст16 [буф -> индекс] )){
        // Успешный разбор шестнадцатеричного числа
        АСДдобавить_токен(дерево, ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть 1;
    	}
    	иначе {
        //ошибка_в_символе(буф -> индекс);
        АСДдобавить_токен(дерево, ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    	}
    }
	}
	буф -> индекс++;
	цел флаг_десятичной_точки = 0;
	цел флаг_экспоненты = 0;
    
	для(;;)
	{
    если ( ЭТО_ЦИФРА( буф -> текст16 [буф -> индекс] ))
    {
    	буф -> индекс++;
    }
    
    иначе если ( буф -> текст16 [буф -> индекс] == 16"2E)
    {
    	если(флаг_десятичной_точки){
        //ошибка вторая точка в числе
        АСДдобавить_токен(дерево, ПЛАВАЮЩАЯ_КОНСТАНТА, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    	}
    	иначе {
        флаг_десятичной_точки = 1;
        буф -> индекс++;
    	
    	}
    }
    иначе если (буф -> текст16 [буф -> индекс] == 16"415 || буф -> текст16 [буф -> индекс] == 16"435 // е Е русские
        	||буф -> текст16 [буф -> индекс] == 16"65 || буф -> текст16 [буф -> индекс] == 16"45) // е Е английские
    {
    	если(флаг_экспоненты){
        //ошибка_в_символе(буф -> индекс);
        АСДдобавить_токен(дерево, ПЛАВАЮЩАЯ_КОНСТАНТА, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    	}
    	иначе {
        флаг_экспоненты = 1;
        буф -> индекс++;
        если(буф -> текст16 [буф -> индекс] == '+' || буф -> текст16 [буф -> индекс] == '-')
        буф -> индекс++;
    	}
    }
    иначе если (ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ( буф -> текст16 [буф -> индекс] ))
    {
    	//массив_токенов [индекс].лексема = ЧИСЛО;
    	если (флаг_десятичной_точки || флаг_экспоненты){
        АСДдобавить_токен(дерево, ПЛАВАЮЩАЯ_КОНСТАНТА, лексема, буф -> индекс - начальный_индекс);
        вернуть 1;
    	}
    	иначе{
        АСДдобавить_токен(дерево, ЦЕЛАЯ_КОНСТАНТА, лексема, буф -> индекс - начальный_индекс);
        вернуть 1;
    	}
    }
    иначе
    {
        АСДдобавить_токен(дерево, ЦЕЛАЯ_КОНСТАНТА, лексема, буф -> индекс - начальный_индекс);
        вернуть ОШИБКА_В_ЧИСЛЕ;
    }
	}
}
//===========================================================================
// Функция распознает идентификаторы
// Запрещено использование кириллицы и латиницы в одном идентификаторе.
//===========================================================================
цел сканировать_идентификатор(ТБуфер *буф, ТАСД *дерево)
{
	если( ЭТО_ЛАТИНИЦА(буф -> текст16 [буф -> индекс])|| ЭТО_КИРИЛЛИЦА(буф -> текст16 [буф -> индекс]) || буф -> текст16 [буф -> индекс] == '_'	)
    ;
	иначе
    вернуть 0;
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	б64 начальный_индекс = буф -> индекс;
	
	для(;;)
	{
    если( ЭТО_ЛАТИНИЦА(буф -> текст16 [буф -> индекс]))
    {	//ОТЛАДКА
    	буф -> индекс++;
    	для(;;){
        если(ЭТО_ЛАТИНИЦА(буф -> текст16 [буф -> индекс]) || ЭТО_ЦИФРА(буф -> текст16 [буф -> индекс])	){ //|| буф -> текст16 [буф -> индекс] == '_'
        	буф -> индекс++;
        	заново;
        }
        прервать;
    	}
    	если(ЭТО_КИРИЛЛИЦА(буф -> текст16 [буф -> индекс]))
        вернуть 2;	//ОШИБКА_В_ИДЕНТИФИКАТОРЕ
    }
    если( ЭТО_КИРИЛЛИЦА(буф -> текст16 [буф -> индекс])){
    	буф -> индекс++;
    	для(;;){
        если(ЭТО_КИРИЛЛИЦА(буф -> текст16 [буф -> индекс]) || ЭТО_ЦИФРА(буф -> текст16 [буф -> индекс]) ){	//|| буф -> текст16 [буф -> индекс] == '_'
        	буф -> индекс++;
        	заново;
        }
        прервать;
    	}
    }
    если( буф -> текст16 [буф -> индекс] == '_'	||  ЭТО_ЦИФРА(буф -> текст16 [буф -> индекс])){
    	буф -> индекс++;
    	заново;
    }
    если(ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ(буф -> текст16 [буф -> индекс])){  //ЭТО_ПРАВЫЙ_РАЗДЕЛИТЕЛЬ
        	симв16 *слово;
        	цел врем = буф ->индекс - начальный_индекс;
        	слово = (симв16 *) malloc((врем)*2+1);
        	memcpy (слово, лексема,(врем)*2);
        	слово[врем]='\0';
        	цел поиск = найти_в_словаре(&словарь_ключевых_слов, слово);
            если (!поиск)
            	поиск = ИДЕНТИФИКАТОР;
        	АСДдобавить_токен(дерево, поиск, лексема, буф -> индекс - начальный_индекс);
        	вернуть 1;
    }    	
    вернуть 2;
	}	
}
//===========================================================================
// Функция распознает комментарии и формирует из них токены
// должна использоваться до обработки операций
//===========================================================================
цел сканировать_коментарии(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	б64 начальный_индекс = буф -> индекс;
	
	если(буф -> текст16 [буф -> индекс] == '/'){
    
    если (буф -> текст16 [буф -> индекс+1] == '/'){
    	//если однострочный комментарий
    	буф -> индекс++;
    	буф -> индекс++;
    	
    	пока(буф -> текст16 [буф -> индекс] != 16"0D && буф -> текст16 [буф -> индекс] != 16"0){
        буф -> индекс++;
    	}
    	АСДдобавить_токен(дерево, КОММЕНТАРИЙ, лексема, буф -> индекс - начальный_индекс);
    	вернуть 1;
    }
	}
	// Для удобства дальнейшей обработки многострочный комментарий "порубим" построчно	
	если(буф -> текст16 [буф -> индекс] == '/'){
    если (буф -> текст16 [буф -> индекс+1] == '*'){
    	//если многострочный комментарий
    	буф -> индекс++;
    	буф -> индекс++;
    	
    	пока(буф -> текст16 [буф -> индекс-1] != '*' || буф -> текст16 [буф -> индекс] != '/' ){
        //выход по достижению конца файла
        если(буф -> текст16 [буф -> индекс] == 16"0)
        	вернуть ОШИБКА_ЗАВЕРШЕНИЯ_КОММЕНТАРИЯ;
        //сканируем конец строки
        если ( буф -> текст16 [буф -> индекс] == 16"0D  && 	буф -> текст16 [буф -> индекс+1]  == 16"0A){
        	//формируем токен КОММЕНТАРИЙ
        	АСДдобавить_токен(дерево, КОММЕНТАРИЙ, лексема, буф -> индекс - начальный_индекс);
    	     
    	     //формируем токен перевод строки
        	лексема = &(буф -> текст16 [буф -> индекс]);
        	буф -> индекс += 2;
        	АСДдобавить_токен(дерево, ПЕРЕВОД_СТРОКИ, лексема, 2);
        	лексема = &(буф -> текст16 [буф -> индекс]);
        	начальный_индекс = буф -> индекс;
        	
        	//продолжаем цикл
        	заново;
        }
        буф -> индекс++;
    	}
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, КОММЕНТАРИЙ, лексема, буф -> индекс - начальный_индекс);
    	вернуть 1;
    }
	}
	если(буф -> текст16 [буф -> индекс] == '*' && буф -> текст16 [буф -> индекс+1] == '/'){
    	//ошибка, буф -> текст16 [буф -> индекс] закрытие комментария раньше открытия
    	//обработаем ошибку на месте.Поместим два символа в токен НЕИЗВЕСТНЫЙ_СИМВОЛ
    	АСДдобавить_токен(дерево, НЕИЗВЕСТНЫЙ_СИМВОЛ, лексема, 2);
    	буф -> индекс += 2;
    	вернуть ОШИБКА_НАЧАЛА_КОММЕНТАРИЯ; //ошибка, буф -> текст16 [буф -> индекс] закрытие комментария раньше открытия
	}
	вернуть 0;	
}
//===========================================================================
// Функция распознает строковые литералы в двойных кавычках
// и символьные в одинарных
// не обрабатывается символ обратного слэша
//===========================================================================
цел сканировать_строку(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	цел флаг_строки16 = 0;
	б64 начальный_индекс = буф -> индекс;
	если(буф -> текст16 [буф -> индекс] == 'L' && буф -> текст16 [буф -> индекс+1] == '\"'){
    буф -> индекс++;
    флаг_строки16 = 1;
	}	
	если(буф -> текст16 [буф -> индекс] == '\"'){
    
    буф -> индекс++;
    пока(буф -> текст16 [буф -> индекс] != '\"' || ( (буф -> текст16 [буф -> индекс-1] == '\\')&&( буф -> текст16 [буф -> индекс-2] != '\\') )){
    	//выход по достижению конца файла
    	если(буф -> текст16 [буф -> индекс] == 16"0) {
        вернуть 2;
    	}
    	буф -> индекс++;
    }
    если (флаг_строки16){
    	АСДдобавить_токен(дерево, СТРОКА16, лексема, буф -> индекс - начальный_индекс+1);//Не понимаю, почему +1
    	
    }
    иначе{
    	АСДдобавить_токен(дерево, СТРОКА, лексема, буф -> индекс - начальный_индекс);
    }
    буф -> индекс++;
    вернуть 1;
    	
	}
	иначе если(буф -> текст16 [буф -> индекс] == '\''){
    буф -> индекс++;
    	
    пока(буф -> текст16 [буф -> индекс] != '\'' || ( (буф -> текст16 [буф -> индекс-1] == '\\')&&( буф -> текст16 [буф -> индекс-2] != '\\') )){
    	//выход по достижению конца файла
    	если(буф -> текст16 [буф -> индекс] == 16"0){
        //буф -> индекс;
        вернуть 2;
    	}
        буф -> индекс++;
    }
    буф -> индекс++;
    АСДдобавить_токен(дерево, СИМВОЛ, лексема, буф -> индекс - начальный_индекс);
    
    	
    вернуть 1;
    	
	}
	вернуть 0;	
}
//===========================================================================
// Функция распознает скобки 
// Скобочный анализатор в данном варианте не нужен
//===========================================================================
цел сканировать_скобки(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	выбор(буф -> текст16 [буф -> индекс]){
	вариант '(':
    буф -> индекс++;
    АСДдобавить_токен(дерево, Л_СКОБКА, лексема, 1);
    вернуть 1;
	вариант ')':
    буф -> индекс++;
    АСДдобавить_токен(дерево, П_СКОБКА, лексема,1);
    вернуть 1;
	вариант '[':
    буф -> индекс++;
    АСДдобавить_токен(дерево, Л_КВ_СКОБКА, лексема, 1);
    вернуть 1;
	вариант ']':
    буф -> индекс++;
    АСДдобавить_токен(дерево, П_КВ_СКОБКА, лексема, 1);
    вернуть 1;
	вариант '{':
    буф -> индекс++;
    АСДдобавить_токен(дерево, Л_ФИГ_СКОБКА, лексема, 1);
    вернуть 1;
	вариант '}':
    буф -> индекс++;
    АСДдобавить_токен(дерево, П_ФИГ_СКОБКА, лексема, 1);
    вернуть 1;
	прочее :
    вернуть 0;
	
	}
    
}
//===========================================================================
// Функция распознает операции (+,-,*,++ и тд)
//===========================================================================
цел сканировать_операции(ТБуфер *буф, ТАСД *дерево)
{
	симв16 *лексема = &буф -> текст16 [буф -> индекс];
	выбор(буф -> текст16 [буф -> индекс]){
	
	вариант '=':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, РАВНО, лексема, 2);
    }
    иначе
        АСДдобавить_токен(дерево, ПРИСВОИТЬ, лексема, 1);
    вернуть 1;
	вариант '+':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ПЛЮС_ПРИСВОИТЬ, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '+'){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ПЛЮС_ПЛЮС, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, ПЛЮС, лексема, 1);
    вернуть 1;
	вариант '-':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, МИНУС_ПРИСВОИТЬ, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '-'){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, МИНУС_МИНУС, лексема, 2);
    }иначе если (буф -> текст16 [буф -> индекс] == '>'){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, СТРЕЛКА, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, МИНУС, лексема, 1);
    вернуть 1;
	вариант '*':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ЗВЕЗДОЧКА_ПРИСВОИТЬ, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, ЗВЕЗДОЧКА, лексема, 1);
    вернуть 1;
	вариант '/':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, СЛЭШ_ПРИСВОИТЬ, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, СЛЭШ, лексема, 1);
    вернуть 1;
	вариант '\\':
    буф -> индекс++;
    АСДдобавить_токен(дерево, ОБРАТНЫЙ_СЛЭШ, лексема, 1);
    вернуть 1;
	вариант '%':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ПРОЦЕНТ_ПРИСВОИТЬ, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, ПРОЦЕНТ, лексема, 1);
    вернуть 1;
	вариант '<':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, МЕНЬШЕ_РАВНО, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '<'){
    	буф -> индекс++;
    	если (буф -> текст16 [буф -> индекс] == '='){
        буф -> индекс++;
    	АСДдобавить_токен(дерево, СДВИГ_ВЛЕВО_ПРИСВОИТЬ, лексема, 3);
    	}
    	иначе
        АСДдобавить_токен(дерево, СДВИГ_ВЛЕВО, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, МЕНЬШЕ, лексема, 1);
    вернуть 1;
	вариант '>':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, БОЛЬШЕ_РАВНО, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '>'){
    	буф -> индекс++;
    	если (буф -> текст16 [буф -> индекс] == '='){
        буф -> индекс++;
        АСДдобавить_токен(дерево, СДВИГ_ВПРАВО_ПРИСВОИТЬ, лексема, 3);
    	}
    	иначе
        АСДдобавить_токен(дерево, СДВИГ_ВПРАВО, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, БОЛЬШЕ, лексема, 1);
    вернуть 1;
	вариант '!':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, НЕ_РАВНО, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, НЕ, лексема, 1);
    вернуть 1;
	вариант '&':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '&'){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ДВ_АМПЕРСЕНД, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, АМПЕРСЕНД_ПРИСВОИТЬ, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, АМПЕРСЕНД, лексема, 1);
    вернуть 1;
	вариант '|':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '|'){ 
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ДВ_ВЕРТ_ЧЕРТА, лексема, 2);
    }
    иначе если (буф -> текст16 [буф -> индекс] == '='){ 
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ВЕРТ_ЧЕРТА_ПРИСВОИТЬ, лексема, 2);
    }
    иначе
    	АСДдобавить_токен(дерево, ВЕРТ_ЧЕРТА, лексема, 1);
    вернуть 1;
	вариант '~':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, ТИЛЬДА_ПРИСВОИТЬ, лексема, 2);// a ~= b
    }
    иначе
    	АСДдобавить_токен(дерево, ТИЛЬДА, лексема, 1);// ~a
    вернуть 1;
	вариант '^':
    буф -> индекс++;
    если (буф -> текст16 [буф -> индекс] == '='){
    	буф -> индекс++;
    	АСДдобавить_токен(дерево, КРЫШКА_ПРИСВОИТЬ, лексема, 2);//a ^= b
    }
    иначе
    АСДдобавить_токен(дерево, КРЫШКА, лексема, 1);//c = a ^ b
    вернуть 1;
	вариант '.' :
    буф -> индекс++;
    АСДдобавить_токен(дерево, ТОЧКА, лексема, 1);
    вернуть 1;
	вариант ',':
    буф -> индекс++;
    АСДдобавить_токен(дерево, ЗАПЯТАЯ, лексема, 1);
    вернуть 1;
	вариант ';':
    буф -> индекс++;
    АСДдобавить_токен(дерево, ТОЧКА_ЗАПЯТАЯ, лексема, 1);
    вернуть 1;
	вариант ':':
    буф -> индекс++;
    АСДдобавить_токен(дерево, ДВОЕТОЧИЕ, лексема, 1);
    вернуть 1;
	прочее :
    вернуть 0;
	
	}
}
//=========================================================================
// Функция помещает ошибочный символ в токен НЕИЗВЕСТНЫЙ_СИМВОЛ
//=========================================================================
пуст обработать_неизвестный_символ(ТБуфер *буф, ТАСД *дерево)
{
	АСДдобавить_токен(дерево, НЕИЗВЕСТНЫЙ_СИМВОЛ, &буф -> текст16 [буф -> индекс], 1);
	буф -> индекс++;
}
//=========================================================================
// Основная функция, осуществляет лексичекий анализ
// на входе ТБуфер *буф, результаты в ТАСД *дерево
//=========================================================================
цел лексер (ТБуфер *буф, ТАСД *дерево)
{ 
	//выделение памяти под массив токенов и начальная инициализация
	АСДподготовить(дерево); 
	
	для ( ; буф -> текст16[буф -> индекс] != '\0'; ) {
    // разбираем последовательность
    //если функция возвращает 	1 - значит успешно, начинаем цикл заново
    //если         	   	0 - значит условие не соблюдено, продолжаем цикл
    //если             >1 - значит ошибка
    
    если( 0 < сканировать_пробельный_символ(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    если( 0 < сканировать_директивы_препроцессора(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    если( 0 < сканировать_число(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    	
    если( 0 < сканировать_строку(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
        
    если( 0 < сканировать_идентификатор(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    если( 0 < сканировать_коментарии(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    	
    если( 0 < сканировать_скобки(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    	
    если( 0 < сканировать_операции(буф, дерево)){
        заново;// Или успешно или произошла ошибка, в обоих случаях начинаем цикл сначала
    	}
    //если дошли до этого места, значит ошибочный символ
    обработать_неизвестный_символ(буф, дерево);
    заново;    
    
	}
	//Завершили сканирование.Добавляем последний токен КОНЕЦ_ФАЙЛА
	АСДдобавить_токен(дерево, КОНЕЦ_ФАЙЛА, &буф -> текст16 [буф -> индекс], 1);
	вернуть 0;
}

0

27

Поиск ключевых слов в словаре сделан со всей пролетарской ненавистью из соплей и палок структур, массивов и циклов. Объявленная функция поиска с помощью хэш-значения фантомная. Не понравился мне результат.
slovar.rh
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c;color:#abb2bf}
</style></head>
<div class="code-box"><strong class="legend" >Код:</strong><div class="blockcode"><div class="scrollbox" style="overflow: auto; height: 40em"><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="macro">#если_нет SLOVAR_RH</span>
<span class="macro">#макрос SLOVAR_RH  </span>

<span class="macro">#макрос    ОБЪЯВЛЕНИЕ </span>
<span class="macro">#вставка     "library.h"</span>

<span class="keyw">тип</span><span class="var"> </span><span class="keyw">структура</span><span class="var"> </span>
{
<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>**<span class="ident">список_слов</span>;
<span class="var"> </span>цел<span class="var"> </span>*<span class="ident">список_значений</span>;
<span class="var"> </span>длин<span class="var"> </span>цел<span class="var"> </span>*<span class="ident">хэш</span>;
<span class="var"> </span>цел<span class="var"> </span>*<span class="ident">индекс</span>;
<span class="var"> </span>цел<span class="var"> </span>*<span class="ident">левый_индекс</span>;
<span class="var"> </span>цел<span class="var"> </span>*<span class="ident">правый_индекс</span>;
<span class="var"> </span>цел<span class="var"> </span><span class="ident">длина</span>;
}<span class="var"> </span><span class="ident">ТСловарь</span>;

<span class="coments">//ТКлюч найти_в_словаре (симв16 **словарь,  ТКлюч *значения, симв16 *слово);</span>
цел<span class="var"> </span><span class="funct">найти_в_словаре</span><span class="var"> </span><span class="del1">(</span><span class="ident">ТСловарь</span><span class="var"> </span>*<span class="ident">словарь</span>,<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>*<span class="ident">слово</span><span class="del1">)</span>;
цел<span class="var"> </span><span class="funct">найти_в_словаре_хэш</span><span class="var"> </span><span class="del1">(</span><span class="ident">ТСловарь</span><span class="var"> </span>*<span class="ident">словарь</span>,<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>*<span class="ident">слово</span><span class="del1">)</span>;

<span class="macro">#конец_если  //SLOVAR_RH</span></pre></td></tr></table></div></div></div>[/html]
slovar.r
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c;color:#abb2bf}
</style></head>
<div class="code-box"><strong class="legend" >Код:</strong><div class="blockcode"><div class="scrollbox" style="overflow: auto; height: 40em"><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   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
  30
  31
  32
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="macro">#вставка     "slovar.rh"</span>
<span class="coments">// Поиск в словаре</span>
<span class="coments">// Сортировка словаря</span>
<span class="coments">// Загрузка словаря из файла</span>
<span class="coments">// Добавление пары в словарь</span>
<span class="coments">// </span>
<span class="coments">//=====================================================</span>
<span class="coments">// неэффективный поиск</span>
<span class="coments">//=====================================================</span>
цел<span class="var"> </span><span class="funct">найти_в_словаре</span><span class="var"> </span><span class="del1">(</span><span class="ident">ТСловарь</span><span class="var"> </span>*<span class="ident">словарь</span>,<span class="var"> </span><span class="ident">симв16</span><span class="var"> </span>*<span class="ident">слово</span><span class="del1">)</span>
{
<span class="var"> </span>цел<span class="var"> </span><span class="ident">левая_граница</span><span class="var"> </span>=<span class="var"> </span><span class="digit">0</span>;
<span class="var"> </span>цел<span class="var"> </span><span class="ident">правая_граница</span><span class="var"> </span>=<span class="var"> </span><span class="ident">словарь</span>-><span class="ident">длина</span><span class="var"> </span>-<span class="digit">1</span>;
<span class="var"> </span>цел<span class="var"> </span><span class="ident">текущий</span><span class="var"> </span>=<span class="var"> </span><span class="ident">правая_граница</span><span class="var"> </span>/<span class="var"> </span><span class="digit">2</span>;<span class="var"> </span>
<span class="var"> </span>цел<span class="var"> </span><span class="ident">результат</span>;
<span class="var"> </span><span class="coments">//ОТЛАДКА16</span>
<span class="var"> </span><span class="oper">пока</span><span class="var"> </span><span class="del1">(</span><span class="ident">результат</span><span class="var"> </span>=<span class="var"> </span><span class="funct">wcscmp</span><span class="var"> </span><span class="del1">(</span><span class="ident">словарь</span>-><span class="ident">список_слов</span><span class="var"> </span>[<span class="ident">текущий</span>],<span class="var"> </span><span class="ident">слово</span><span class="del1">)</span><span class="del1">)</span><span class="var"> </span>
<span class="var"> </span>{
<span class="var">    </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="ident">результат</span><span class="var"> </span><span class="del2">&gt;</span><span class="var"> </span><span class="digit">0</span><span class="del1">)</span>{
<span class="var">    </span><span class="ident">правая_граница</span><span class="var"> </span>=<span class="var"> </span><span class="ident">текущий</span><span class="var"> </span>-<span class="digit">1</span><span class="var"> </span>;
<span class="var">    </span><span class="ident">текущий</span><span class="var"> </span>=<span class="var"> </span><span class="del1">(</span><span class="ident">левая_граница</span><span class="var"> </span>+<span class="var"> </span><span class="ident">правая_граница</span><span class="del1">)</span><span class="var"> </span>/<span class="var"> </span><span class="digit">2</span>;
<span class="var">    </span>}
<span class="var">    </span><span class="oper">иначе</span>{
<span class="var">    </span><span class="ident">левая_граница</span><span class="var"> </span>=<span class="var"> </span><span class="ident">текущий</span><span class="var"> </span>+<span class="var"> </span><span class="digit">1</span>;
<span class="var">    </span><span class="ident">текущий</span><span class="var"> </span>=<span class="var"> </span><span class="del1">(</span><span class="ident">левая_граница</span><span class="var"> </span>+<span class="var"> </span><span class="ident">правая_граница</span><span class="del1">)</span><span class="var"> </span>/<span class="var"> </span><span class="digit">2</span>;
<span class="var">    </span>}
<span class="var">    </span><span class="oper">если</span><span class="var"> </span><span class="del1">(</span><span class="del1">(</span><span class="ident">правая_граница</span><span class="var"> </span>-<span class="var"> </span><span class="ident">левая_граница</span><span class="del1">)</span><span class="var"> </span><span class="del2">&lt;</span><span class="var"> </span><span class="digit">0</span><span class="del1">)</span>
<span class="var">    </span><span class="oper">вернуть</span><span class="var"> </span><span class="digit">0</span>;<span class="var"> </span><span class="coments">//если не найдено</span>
<span class="var">    </span>
<span class="var"> </span>}<span class="var"> </span>
<span class="var"> </span><span class="oper">вернуть</span><span class="var"> </span><span class="ident">словарь</span>-><span class="ident">список_значений</span><span class="var"> </span>[<span class="ident">текущий</span>];
}</pre></td></tr></table></div></div></div>[/html]

Отредактировано Евгений (2022-05-12 10:23:43)

0

28

Осталось совсем немножко. Но задачка... пальчики оближешь - подсчитать сколько нужно место выделить под будущий html-код. Как только ее решу, выложу html-генератор. Ну и основной файл main. Конечно у нашей программы нет никакого интерфейса пользователя, но это я уже на досуге позанимаюсь. Думаю, для лабораторного стенда полученный результат уже неплох.

Отредактировано Евгений (2022-05-12 00:42:18)

0

29

Генератор html-кода. Формирует общую структуру html, вставляет таблицу из двух ячеек. В первой нумерация, во второй текст исходника. Тест складывается из лексем, которые по необходимости оборачиваются html-тэгами для подсветки синтаксиса. Одна из функций проверяет, является ли идентификатор именем функции. Генератор работает за два прохода. Сначала пробегает весь массив токенов и подсчитывает необходимое место. Второй раз уже формируется выходной html-код. Как всегда два файла.
html_gen.rh
[html]<head>
<meta charset="UTF-8"><style>
.code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}
.coments {color:#707070;font-style:italic}
.digit {color:#ff3a83}
.del1 {color:#a6deff}
.del2 {color:#ffaa00}
.oper {color:#f6f080}
.keyw {color:#37a8ed}
.var {color:#ffffff}
.ident {color:#ffffff}
.funct {color:#a6deff}
.str {color:#80ff80;font-style:italic}
.macro {color:#9f9fd0;font-style:italic}
LI {background:#2b211c; padding:0.2em; padding-left:0.5em}
.rownumber {background:#3b312c;color:#abb2bf}
</style></head>
<div class="code-box"><strong class="legend" >Код:</strong><div class="blockcode"><div class="scrollbox" style="overflow: auto; height: 40em"><table class = "code"><tr><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "rownumber" style="margin: 0; line-height: 150%">   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
</pre></td><td style="border: 1px solid #2b211c;background:#2b211c"><pre class = "code" style="margin: 0; line-height: 150%"><span class="macro">#если_нет HTML_GEN_H</span>
<span class="macro">#макрос   HTML_GEN_H </span>
<span class="coments">//===========================================================</span>
<span class="coments">// Файл:    html_gen.rh</span>
<span class="coments">// Версия:    1.01</span>
<span class="coments">// Дата:    20:44 08.05.2022</span>
<span class="coments">// Описание: </span>
<span class="coments">// Автор:</span>
<span class="coments">//===========================================================</span>
<span class="macro">#вставка "library.h"</span>
<span class="macro">#вставка "textbuffer.h"</span>
<span class="macro">#вставка "ASTtree.h"</span>

цел<span class="var"> </span><span class="funct">генерировать_html</span><span class="del1">(</span><span class="ident">ТБуфер</span><span class="var"> </span>*<span class="ident">код_html</span>,<span class="var"> </span><span class="ident">ТАСД</span><span class="var"> </span>*<span class="ident">дерево</span><span class="del1">)</span>;

<span class="macro">#к_если    //HTML_GEN_H</span>

</pre></td></tr></table></div></div></div>[/html]

0

30

Этот файл без подсветки по двум причинам. Во первых не влезает. А во вторых он содержит html-тэги, которые сильно его перекашивают. Неожиданный эффект:)
html_gen.r

Код:
//===========================================================
// 	Файл:    html_gen.r
// 	Версия:    1.01
// 	Дата:    20:50 08.05.2022
//	Описание:	На основе массива токенов генерируется html-код
//        для подсветки синтаксиса на веб-странице 
//	Автор:
//===========================================================
#вставка	"html_gen.h"
//===========================================================
// Подсчитываем сколько строк в тесте
//===========================================================
цел сколько_строк(ТАСД *дерево)
{
	цел количество_строк = 1;
	дерево->индекс_токена = 1;
	для(дерево->индекс_токена = 1; дерево->индекс_токена < дерево->всего_токенов-1; дерево->индекс_токена++)
	{
    если(АСДтокен(дерево) == ПЕРЕВОД_СТРОКИ)
    	количество_строк++;
	}
	вернуть количество_строк;
}
//===========================================================
// Проверяем, является ли идентификатор именем фунции
//===========================================================
цел проверить_функция_ли(ТАСД *дерево)
{
	дерево->индекс_токена++;
	если (АСДтокен(дерево)==Л_СКОБКА)
	{ //то очень вероятно, что перед нами функция
	  //но возможен случай объявления указателя на фунцию:  пуст (*указатель_на_фунцию) (цел, цел)	
    дерево->индекс_токена++;
    если ((АСДтокен(дерево)==ЗВЕЗДОЧКА) || (АСДтокен(дерево)==ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ && АСДтокен1(дерево)==ЗВЕЗДОЧКА)){
    	//это не функция
    	дерево->индекс_токена -= 2;
    	вернуть 0;
    }иначе{
    	дерево->индекс_токена -= 2;
    	вернуть 1;
    }
    
	}
	если (АСДтокен(дерево)==ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ && АСДтокен1(дерево)==Л_СКОБКА)
	{ //то очень вероятно, что перед нами функция
	  //но возможен случай объявления указателя на фунцию:  пуст (*указатель_на_фунцию) (цел, цел)	
    дерево->индекс_токена += 2;
    если ((АСДтокен(дерево)==ЗВЕЗДОЧКА) || (АСДтокен(дерево)==ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ && АСДтокен1(дерево)==ЗВЕЗДОЧКА)){
    	//это не функция
    	дерево->индекс_токена -=3;
    	вернуть 0;
    }иначе{
    	дерево->индекс_токена -=3;
    	вернуть 1;
    }
	}
	дерево->индекс_токена--;
	вернуть 0;
	
}
//===========================================================
// Копируем строку в буфер
// Функция также используется для подсчета требуемого места
// Для этого в качестве буф передается нулевой указатель
//===========================================================

цел копировать_строку16_в_буфер(симв16 *буф, симв16 *строка)
{	
	цел индекс;
	для (индекс = 0; строка[индекс] !='\0'; индекс++  ){
    если (буф != НОЛЬ){
    	буф[индекс] = строка[индекс];
    }
	}
	если (буф != НОЛЬ)
    буф[индекс] = строка[индекс];
	вернуть индекс;
}
//===========================================================
// Функция считает, сколько места нужно для копирования лексемы
//===========================================================
цел посчитать_лексему_в_буфер(симв16 *буф, ТАСД *дерево)
{
	цел индекс;
	цел добавлено = 0;
        
	выбор (АСДтокен(дерево))
	{
    вариант ПЕРЕВОД_СТРОКИ:
        вернуть 2;	
    вариант МЕНЬШЕ:
        вернуть 30;	
    вариант МЕНЬШЕ_РАВНО:
        вернуть 31;	
    вариант БОЛЬШЕ:
        вернуть 30;	
    вариант БОЛЬШЕ_РАВНО:
        вернуть 31;	
    вариант АМПЕРСЕНД:
        вернуть 31;	
    вариант ДВ_АМПЕРСЕНД:
        вернуть 36;	
    вариант АМПЕРСЕНД_ПРИСВОИТЬ:
        вернуть 32;	
    вариант СТРОКА:
        вернуть 36 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
        прервать;
    вариант СТРОКА16:
        вернуть 35 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КОММЕНТАРИЙ:
        вернуть 29 + добавлено + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ЦЕЛАЯ_КОНСТАНТА:
    вариант ПЛАВАЮЩАЯ_КОНСТАНТА:
    вариант ДВОИЧНОЕ_ЧИСЛО:
    вариант ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО:
        вернуть 27 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ:
    вариант Л_КВ_СКОБКА:
    вариант П_КВ_СКОБКА:
    вариант Л_ФИГ_СКОБКА:
    вариант П_ФИГ_СКОБКА:
    вариант ПЛЮС    :
    вариант МИНУС    :
    вариант ЗВЕЗДОЧКА 	:
    вариант СЛЭШ     :
    вариант ОБРАТНЫЙ_СЛЭШ     :
    вариант ПРОЦЕНТ    :
    вариант ПЛЮС_ПЛЮС    	:
    вариант МИНУС_МИНУС    	:
    вариант ПЛЮС_ПРИСВОИТЬ    :
    вариант МИНУС_ПРИСВОИТЬ    :
    вариант ЗВЕЗДОЧКА_ПРИСВОИТЬ	:
    вариант СЛЭШ_ПРИСВОИТЬ    :
    вариант ПРОЦЕНТ_ПРИСВОИТЬ	:
    вариант НЕ    :
    вариант НЕ_РАВНО:
    вариант ДВ_ВЕРТ_ЧЕРТА    :
    вариант ВЕРТ_ЧЕРТА    	:
    вариант ВЕРТ_ЧЕРТА_ПРИСВОИТЬ:
    вариант ТИЛЬДА        :
    вариант ТИЛЬДА_ПРИСВОИТЬ	:
    вариант КРЫШКА        :
    вариант КРЫШКА_ПРИСВОИТЬ	:
    вариант ПРИСВОИТЬ    	:
    вариант СТРЕЛКА        :
    вариант ТОЧКА        :
    вариант ЗАПЯТАЯ        :
    вариант ТОЧКА_ЗАПЯТАЯ    :
    вариант ДВОЕТОЧИЕ    	:
    вариант ТИП:
        вернуть  дерево->узлы[дерево->индекс_токена].длина_лексемы; //26 +
    вариант Л_СКОБКА:
    вариант П_СКОБКА:
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ДИРЕКТИВА_ПРЕПРОЦЕССОРА:
        добавлено = 0;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	//ищем и заменяем символы '<' '>'
        	если (дерево->узлы[дерево->индекс_токена].лексема[индекс]=='<'){
            добавлено +=3;
            заново;	
        	}
        	если (дерево->узлы[дерево->индекс_токена].лексема[индекс]=='>'){
            добавлено +=3;
            заново;	
        	}
        }
        вернуть 27 + добавлено + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ИДЕНТИФИКАТОР:
        вернуть 27 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ОПЕРАТОР:
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КЛЮЧЕВОЕ_СЛОВО:
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант СИМВОЛ:
        вернуть 25 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант НЕИЗВЕСТНЫЙ_СИМВОЛ:
        вернуть 47 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КОНЕЦ_ФАЙЛА:
        вернуть 1;
    прочее:
        вернуть 25 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        
	}
	вернуть 1;
	
	
}
//===================================================================
// Фунция копирует лексему в буфер
//===================================================================
цел копироватьь_лексему_в_буфер(симв16 *буф, ТАСД *дерево)
{
	цел индекс;
	цел добавлено = 0;
        
	выбор (АСДтокен(дерево))
	{
    вариант ПЕРЕВОД_СТРОКИ:
        копировать_строку16_в_буфер (буф, L"\r\n");
        вернуть 2;	
    вариант МЕНЬШЕ:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&lt;</span>");
        вернуть 30;	
    вариант МЕНЬШЕ_РАВНО:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&lt;=</span>");	
        вернуть 31;	
    вариант БОЛЬШЕ:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&gt;</span>");
        вернуть 30;	
    вариант БОЛЬШЕ_РАВНО:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&gt=;</span>");	
        вернуть 31;	
    вариант АМПЕРСЕНД:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&amp;</span>");	
        вернуть 31;	
    вариант ДВ_АМПЕРСЕНД:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&amp;&amp;</span>");	
        вернуть 36;	
    вариант АМПЕРСЕНД_ПРИСВОИТЬ:
        копировать_строку16_в_буфер (буф, L"<span class=\"del2\">&amp;=</span>");	
        вернуть 32;	
    вариант СТРОКА:
        копировать_строку16_в_буфер (буф, L"<span class=\"str\">&quot;");	
        буф += 23;
        для (индекс = 1; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"&quot;</span>");	
        вернуть 36 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант СТРОКА16:
        копировать_строку16_в_буфер (буф, L"<span class=\"str\">L&quot;");	
        буф += 23;
        для (индекс = 2; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы-1;
        
        копировать_строку16_в_буфер (буф, L"&quot;</span>");	
        вернуть 35 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КОММЕНТАРИЙ:
        добавлено = 0;
        копировать_строку16_в_буфер (буф, L"<span class=\"coments\">");	
        буф += 22;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	если (дерево->узлы[дерево->индекс_токена].лексема[индекс]=='\r'){
            если (дерево->узлы[дерево->индекс_токена].лексема[индекс+1]=='\n'){
            	копировать_строку16_в_буфер (&буф[индекс], L"</span>\r\n<li><span class=\"coments\">");
            	буф += 33;
            	добавлено += 33;
            	индекс++;
            }
        	}
        	иначе{
            буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        	}	
        	
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 29 + добавлено + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ЦЕЛАЯ_КОНСТАНТА:
    вариант ПЛАВАЮЩАЯ_КОНСТАНТА:
    вариант ДВОИЧНОЕ_ЧИСЛО:
    вариант ШЕСТНАДЦАТЕРИЧНОЕ_ЧИСЛО:
        копировать_строку16_в_буфер (буф, L"<span class=\"digit\">");	
        буф += 20;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 27 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ПРОБЕЛЬНАЯ_ПОСЛЕДОВАТЕЛЬНОСТЬ:
    вариант Л_КВ_СКОБКА:
    вариант П_КВ_СКОБКА:
    вариант Л_ФИГ_СКОБКА:
    вариант П_ФИГ_СКОБКА:
    вариант ПЛЮС    :
    вариант МИНУС    :
    вариант ЗВЕЗДОЧКА 	:
    вариант СЛЭШ     :
    вариант ОБРАТНЫЙ_СЛЭШ     :
    вариант ПРОЦЕНТ    :
    вариант ПЛЮС_ПЛЮС    	:
    вариант МИНУС_МИНУС    	:
    вариант ПЛЮС_ПРИСВОИТЬ    :
    вариант МИНУС_ПРИСВОИТЬ    :
    вариант ЗВЕЗДОЧКА_ПРИСВОИТЬ	:
    вариант СЛЭШ_ПРИСВОИТЬ    :
    вариант ПРОЦЕНТ_ПРИСВОИТЬ	:
    вариант НЕ    :
    вариант НЕ_РАВНО:
    вариант ДВ_ВЕРТ_ЧЕРТА    :
    вариант ВЕРТ_ЧЕРТА    	:
    вариант ВЕРТ_ЧЕРТА_ПРИСВОИТЬ:
    вариант ТИЛЬДА        :
    вариант ТИЛЬДА_ПРИСВОИТЬ	:
    вариант КРЫШКА        :
    вариант КРЫШКА_ПРИСВОИТЬ	:
    вариант ПРИСВОИТЬ    	:
    вариант СТРЕЛКА        :
    вариант ТОЧКА        :
    вариант ЗАПЯТАЯ        :
    вариант ТОЧКА_ЗАПЯТАЯ    :
    вариант ДВОЕТОЧИЕ    	:
    вариант ТИП:
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        вернуть  дерево->узлы[дерево->индекс_токена].длина_лексемы; //26 +
    вариант Л_СКОБКА:
    вариант П_СКОБКА:
        копировать_строку16_в_буфер (буф, L"<span class=\"del1\">");	
        буф += 19;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ДИРЕКТИВА_ПРЕПРОЦЕССОРА:
        копировать_строку16_в_буфер (буф, L"<span class=\"macro\">");	
        буф += 20;
        добавлено = 0;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	//ищем и заменяем символы '<' '>'
        	если (дерево->узлы[дерево->индекс_токена].лексема[индекс]=='<'){
            копировать_строку16_в_буфер (&буф[индекс], L"&lt;");
            буф += 3;
            добавлено +=3;
            заново;	
        	}
        	если (дерево->узлы[дерево->индекс_токена].лексема[индекс]=='>'){
            копировать_строку16_в_буфер (&буф[индекс], L"&gt;");
            буф += 3;
            добавлено +=3;
            заново;	
        	}
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 27 + добавлено + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ИДЕНТИФИКАТОР:
        если (проверить_функция_ли(дерево)){
        	копировать_строку16_в_буфер (буф, L"<span class=\"funct\">");	
        }иначе{
        	копировать_строку16_в_буфер (буф, L"<span class=\"ident\">");
        }
        буф += 20;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 27 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант ОПЕРАТОР:
        копировать_строку16_в_буфер (буф, L"<span class=\"oper\">");	
        буф += 19;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КЛЮЧЕВОЕ_СЛОВО:
        копировать_строку16_в_буфер (буф, L"<span class=\"keyw\">");	
        буф += 19;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 26 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант СИМВОЛ:
        копировать_строку16_в_буфер (буф, L"<span class=\"str\">");	
        буф += 18;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 25 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант НЕИЗВЕСТНЫЙ_СИМВОЛ:
        // Обводим неизвестный символ красной рамочкой
        копировать_строку16_в_буфер (буф, L"<span style=\"border: 1px solid #FF0000\">");	
        буф += 40;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 47 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
    вариант КОНЕЦ_ФАЙЛА:
        копировать_строку16_в_буфер (буф, L" ");	
        вернуть 1;
    прочее:
        копировать_строку16_в_буфер (буф, L"<span class=\"var\">");	
        буф += 18;
        для (индекс = 0; индекс < дерево->узлы[дерево->индекс_токена].длина_лексемы; индекс++  ){
        	буф[индекс] = дерево->узлы[дерево->индекс_токена].лексема[индекс];
        }
        буф += дерево->узлы[дерево->индекс_токена].длина_лексемы;
        копировать_строку16_в_буфер (буф, L"</span>");	
        вернуть 25 + дерево->узлы[дерево->индекс_токена].длина_лексемы;
        
        
	}
	
	буф[индекс] = '\0';
	вернуть индекс;
	
	
}
цел генерировать_html(ТБуфер *код_html, ТАСД *дерево)
{	//================================================================
	// Подсчитываем необходимое место под html-код
	//================================================================
	дерево->индекс_токена = 1;
	симв16 *буф = НОЛЬ;
	цел записано = 0;
	//Считаем сколько строк в файле. Нужно для нумерации строк
	цел всего_строк = сколько_строк(дерево);
	симв16 врем[12];
	//Считаем сколько нужно места для нумерации
	для (дерево->индекс_токена = 1;дерево->индекс_токена <= всего_строк ; дерево->индекс_токена++ ){
    если (всего_строк < 1000){
    	swprintf(врем,L" %3u \r\n",дерево->индекс_токена);
    }
    иначе{
    	swprintf(врем,L" %4u \r\n",дерево->индекс_токена);
    }
    записано += копировать_строку16_в_буфер(буф,врем);
	}
	//Считаем сколько нужно места на лексемы вместе с подсветкой
	для (дерево->индекс_токена = 1; дерево->индекс_токена < дерево->всего_токенов ; дерево->индекс_токена++ ){
    записано += посчитать_лексему_в_буфер(буф,дерево);
	}
	//======================================================================================
	// Сколько насчитали, столько и выделяем 
	// 1067 символов составляет неизменяемая часть html-кода
	//======================================================================================
	код_html->текст16 = (симв16 *) malloc((записано + 1067+2)*sizeof(симв16));
	код_html->длина_текста16 = записано + 1067+2;
	
	//======================================================================================
	// Записываем в буфер html-код
	//======================================================================================
	буф = код_html->текст16;
	записано = 0;
	// заголовочная часть
	записано += копировать_строку16_в_буфер(буф,L"[html]<head>\r\n<meta charset=\"UTF-8\"><style>\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".code{display:block;overflow-x:auto;color:#ffaa00;font-family:'Courier New'; font-size:10pt;tab-size: 4;background:#2b211c}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".coments {color:#707070;font-style:italic}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".digit {color:#ff3a83}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".del1 {color:#a6deff}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".del2 {color:#ffaa00}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".oper {color:#f6f080}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".keyw {color:#37a8ed}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".var {color:#ffffff}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".ident {color:#ffffff}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".funct {color:#a6deff}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".str {color:#80ff80;font-style:italic}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".macro {color:#9f9fd0;font-style:italic}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L"LI {background:#2b211c; padding:0.2em; padding-left:0.5em}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L".rownumber {background:#3b312c;color:#abb2bf}\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L"</style></head>\r\n");
	буф = код_html->текст16 + записано;
	записано += копировать_строку16_в_буфер(буф,L"<div class=\"code-box\"><strong class=\"legend\" >Код:</strong><div class=\"blockcode\"><div class=\"scrollbox\" style=\"overflow: auto; height: 40em\"><table class = \"code\"><tr><td style=\"border: 1px solid #2b211c;background:#2b211c\"><pre class = \"rownumber\" style=\"margin: 0; line-height: 150%\">");//
	буф = код_html->текст16 + записано;                        	
	// затем нумерация строк
	всего_строк = сколько_строк(дерево);
	 врем[12];
	для (дерево->индекс_токена = 1;дерево->индекс_токена <= всего_строк ; дерево->индекс_токена++ ){
    если (всего_строк < 1000){
    	swprintf(врем,L" %3u \r\n",дерево->индекс_токена);
    }
    иначе{
    	swprintf(врем,L" %4u \r\n",дерево->индекс_токена);
    }
    записано += копировать_строку16_в_буфер(буф,врем);
    буф = код_html->текст16 + записано;
	}
	// основная часть
	записано += копировать_строку16_в_буфер(буф,L"</pre></td><td style=\"border: 1px solid #2b211c;background:#2b211c\"><pre class = \"code\" style=\"margin: 0; line-height: 150%\">");//
    буф = код_html->текст16 + записано;
	для (дерево->индекс_токена = 1; дерево->индекс_токена < дерево->всего_токенов ; дерево->индекс_токена++ ){
    записано += копироватьь_лексему_в_буфер(буф,дерево);
    буф = код_html->текст16 + записано;
	}
	// завершение html-кода. Закрытие тэгов
	записано += копировать_строку16_в_буфер(буф,L"</pre></td></tr></table></div></div></div>[/html]");
    буф = код_html->текст16 + записано;
	// Отладка
	пчтф16(L"Подсчитано: %i, реально занимает: %i",записано, wcslen(код_html->текст16));
	читз();
	вернуть 0;
}



   

Отредактировано Евгений (2022-05-12 20:48:52)

0