Я просто высказал своё мнение. И это нормально, что наши мнения не совпадают, так как каждому удобно по разному воспринимать информацию.
А про то что вы не поняли это ни как не связано со статьёй, так как он использует готовый фреймворк для написания языка программирования, а я свой с полного нуля, очень грубо говоря свой фреймворк.
Я лишь хотел поделиться своими наработками.
А дать определение модульного парсера к сожалению не могу так как это лишь идея проекта без какой либо конкретики. И вот из-за того что я не совсем понимаю как эту конкретику сформулировать я пока остановился.
И да согласен, что от порядка сканеров лексика может нарушиться. Но в моем представлении лексер выглядит модульным.
Наверняка статья очень интересная, но пока к сожалению столь длинное чтиво читать не очень хочется. Может быть потом прочитаю.
Можно было бы наверное разделить на несколько статей где подробно рассказывается отдельно лексер, отдельно парсер, отдельно синтаксическое дерево и т.д.. Так оно и психологически проще читать было бы.
А так я сюда спустился для того чтобы просто поделиться своей маленькой наработкой над которой работал недавно, но забросил пока из-за нехватки знаний.
Я тоже ради интереса писал свой C подобный язык программирования. Но смог реализовать пока лишь лексер. У меня была задумка модульности написания, так чтобы можно было добавлять в язык новые возможности постепенно без полного переписывания кода. Для этого я реализовал префиксное дерево для быстрого поиска ключевых слов. А для лексера сканеры. И у меня получилось нечто подобное:
std::vector контейнер предназначенный для выделения блока памяти вот смотри:
[1][2][3][4][5]
^
ты хочешь удалить этот объект
что происходит в векторе:
1шаг: 4 элемент перемещаем в 3
обычно при этом в объекте ктороый перемещают затирается его старая информация
[1][2][4][0][5]
тепрь старый 4 элемент пустой но он ещё существует
2шаг: 5 элемент перемещаем в 4 элемент
[1][2][4][5][0]
теперь старый 5 элемент обнулен но всё ещё находится в памяти
3шаг: вызываем деструктор у последнего элемента
[1][2][4][5][NULL]
последний элемент удалён но нужно помнить что в векторе память уже была выделена память под 5 элементов
поэтому последний элемент всё ещё занимает память но он не инециализирован
если тебя смущает это то тебе необходимо использовать std::list или std::forward_list
Добавь к классу Object ещё конструкторы и операторы копирования, перемещения с выводом в консоль запусти свой код ещё раз и посмотри результат.
П.С. при использовании метода erase все последующие объекты применяют методы перемещения чтобы занять место в памяти у удаляемого объекта. И так получается, что на место последнего никого нет, но память нужно освободить. Вот и вызывается деструктор у последнего.
Вряд ли смогу точно сказать, но по-моему меньше 5 секунд для 25х25. А для 36х36 я просто ждал около минуты ничего не происходило, ну и выключал программу
Читал, читал и как то не понял прикола с опорными точками. Ты типо собираешься относительно опорных точек подбирать значения?
Я как то давно делал авторешатель судоку. (Только я работал с кодом на C++, но это не важно).
У меня было несколько этапов:
1) сбор полной информации о всех свободных клеток (при этом собирал я их в разные массивы: общий где абсолютно все клетки, клетки находящиеся в одном большом квадрате, по горизонтали, по вертикали. получились 4 блока для анализа)
2) для каждой свободной клетки я собирал массив из возможных вариантов (для этой цели я использовал массив битов, для того чтобы хоть как-то сэкономить на памяти, то есть соответственно 0 бит отвечал за число 1, 2 бит за число 3 ну и так далее)
3) я проводил анализ каждого блока (из 1 этапа) для массива, где хранятся все свободные клетки, я искал клетки у которых имеется единственное возможное значение после чего записывал его и удалял клетку из всех блоков. Для остальных блоков была задача на поиск единственного возможного значения, которого нет в других клетках, ну и снова записывал его и удалял из всех блоков.
4) провожу проверку на то что решено (индикатором являлся размер 1 блока)
5) проверяю на ошибки (в возможных вариантах клетки отсутствуют варианты, это единственный способ проверки мне тогда пришел в голову)
6) если в 3 этапе была совершена хотя бы 1 запись то возвращался к 3 этапу, в противном случае я искал клетку с минимально возможным количеством вариантов. (Самый желанный вариант это клетка с 2 возможными значениями) Копировал всё данные и в копию подставлял возможный вариант и отправлял копированные данные на 3 этап и так далее пока не решится или не обнаружится ошибка.
В принципе мой алгоритм справлялся с судоку размером 25х25, но с 36х36 уже слишком долго выполняется.
Сейчас у меня есть пара мыслей как можно оптимизировать алгоритм, но если честно просто лень
Прикольно, но хотелось бы больше получить информации о реализации внутренней структуры кода. (Да я увидел ссылку на гитхаб, но мне бы хотелось узнать мысли о том как пришёл к такому решению) хотя наверное это не совсем статья это больше самореклама.
Ещё я так понял у тебя логгер поддерживает только строки, что не всегда удобно, если например нужно для отладки отправить числа какие-нибудь с сообщением что конкретно происходит. Это конечно можно решить с помощью конкатенации строк и чисел, но всё равно не совсем удобно.
Я например делал свой логгер, пару месяцев назад (ещё не доделал) вот пример моей реализации:
В моем случае я пытался сохранить привычный синтаксис std::cout. Да я знаю, что использовать define DEBUG не лучшая идея, но это просто временная реализация для тестов. пока не совсем придумал, как лучше сделать.
Я просто высказал своё мнение. И это нормально, что наши мнения не совпадают, так как каждому удобно по разному воспринимать информацию.
А про то что вы не поняли это ни как не связано со статьёй, так как он использует готовый фреймворк для написания языка программирования, а я свой с полного нуля, очень грубо говоря свой фреймворк.
Я лишь хотел поделиться своими наработками.
А дать определение модульного парсера к сожалению не могу так как это лишь идея проекта без какой либо конкретики. И вот из-за того что я не совсем понимаю как эту конкретику сформулировать я пока остановился.
И да согласен, что от порядка сканеров лексика может нарушиться. Но в моем представлении лексер выглядит модульным.
Наверняка статья очень интересная, но пока к сожалению столь длинное чтиво читать не очень хочется. Может быть потом прочитаю.
Можно было бы наверное разделить на несколько статей где подробно рассказывается отдельно лексер, отдельно парсер, отдельно синтаксическое дерево и т.д.. Так оно и психологически проще читать было бы.
А так я сюда спустился для того чтобы просто поделиться своей маленькой наработкой над которой работал недавно, но забросил пока из-за нехватки знаний.
Я тоже ради интереса писал свой C подобный язык программирования. Но смог реализовать пока лишь лексер. У меня была задумка модульности написания, так чтобы можно было добавлять в язык новые возможности постепенно без полного переписывания кода. Для этого я реализовал префиксное дерево для быстрого поиска ключевых слов. А для лексера сканеры. И у меня получилось нечто подобное:
Скрытый текст
А потом я просто столкнулся с тем, что не понимаю как реализовать модульный парсер. Поэтому пока забросил
std::vector контейнер предназначенный для выделения блока памяти вот смотри:
если тебя смущает это то тебе необходимо использовать std::list или std::forward_list
тут например каждый элемент имеет связь со своими соседями, но при этом они находятся в разных участках памяти
удаление происходит так:
тоесть соседи у удаляемого объекта забывают про него и знакомятся с новым соседом
а std::forward почти как std::list но объекты не имеют связи с предыдущими соседями тоесть:
Но из-за такого распределения памяти выходит проблематичным получение произвольного объекта по индексу
Лучше изучите стандартные контейнеры STL
Добавь к классу Object ещё конструкторы и операторы копирования, перемещения с выводом в консоль запусти свой код ещё раз и посмотри результат.
П.С. при использовании метода erase все последующие объекты применяют методы перемещения чтобы занять место в памяти у удаляемого объекта. И так получается, что на место последнего никого нет, но память нужно освободить. Вот и вызывается деструктор у последнего.
А понял. Да пробовал решалось. Так как в моем алгоритме используется перебор когда больше нет единственного варианта.
Ах да ещё не забудь проверить работоспособность свой алгоритм в случае если судоку выдан с ошибкой, изначально.
В каком смысле на Эвересте?
П.С. я для тестов алгоритма брал из интернета самые сложные варианты судоку.
Вряд ли смогу точно сказать, но по-моему меньше 5 секунд для 25х25. А для 36х36 я просто ждал около минуты ничего не происходило, ну и выключал программу
Читал, читал и как то не понял прикола с опорными точками. Ты типо собираешься относительно опорных точек подбирать значения?
Я как то давно делал авторешатель судоку. (Только я работал с кодом на C++, но это не важно).
У меня было несколько этапов:
1) сбор полной информации о всех свободных клеток (при этом собирал я их в разные массивы: общий где абсолютно все клетки, клетки находящиеся в одном большом квадрате, по горизонтали, по вертикали. получились 4 блока для анализа)
2) для каждой свободной клетки я собирал массив из возможных вариантов (для этой цели я использовал массив битов, для того чтобы хоть как-то сэкономить на памяти, то есть соответственно 0 бит отвечал за число 1, 2 бит за число 3 ну и так далее)
3) я проводил анализ каждого блока (из 1 этапа) для массива, где хранятся все свободные клетки, я искал клетки у которых имеется единственное возможное значение после чего записывал его и удалял клетку из всех блоков. Для остальных блоков была задача на поиск единственного возможного значения, которого нет в других клетках, ну и снова записывал его и удалял из всех блоков.
4) провожу проверку на то что решено (индикатором являлся размер 1 блока)
5) проверяю на ошибки (в возможных вариантах клетки отсутствуют варианты, это единственный способ проверки мне тогда пришел в голову)
6) если в 3 этапе была совершена хотя бы 1 запись то возвращался к 3 этапу, в противном случае я искал клетку с минимально возможным количеством вариантов. (Самый желанный вариант это клетка с 2 возможными значениями) Копировал всё данные и в копию подставлял возможный вариант и отправлял копированные данные на 3 этап и так далее пока не решится или не обнаружится ошибка.
В принципе мой алгоритм справлялся с судоку размером 25х25, но с 36х36 уже слишком долго выполняется.
Сейчас у меня есть пара мыслей как можно оптимизировать алгоритм, но если честно просто лень
Статья понравилась, жалко у меня не хватает кармы, чтобы повысить вам карму.
Узнал немного нового о compile time. Даже появилась идея, как возможно можно решить одну старую задумку, которая у меня до этого не получалась.
Когда-то давно тоже делал игру в жизнь, но с возможностью менять правила жизни мира в процессе выполнения.
П.С. Спасибо за статью)
Прикольно, но хотелось бы больше получить информации о реализации внутренней структуры кода. (Да я увидел ссылку на гитхаб, но мне бы хотелось узнать мысли о том как пришёл к такому решению) хотя наверное это не совсем статья это больше самореклама.
Ещё я так понял у тебя логгер поддерживает только строки, что не всегда удобно, если например нужно для отладки отправить числа какие-нибудь с сообщением что конкретно происходит. Это конечно можно решить с помощью конкатенации строк и чисел, но всё равно не совсем удобно.
Я например делал свой логгер, пару месяцев назад (ещё не доделал) вот пример моей реализации:
Скрытый текст
В моем случае я пытался сохранить привычный синтаксис std::cout. Да я знаю, что использовать define DEBUG не лучшая идея, но это просто временная реализация для тестов. пока не совсем придумал, как лучше сделать.