Введение

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

Примечание. Прежде чем продолжить, обратите внимание, что для этой статьи требуются предварительные знания и опыт программирования. Это потому, что ближе к концу мы разрабатываем систему ошибок языка программирования с разными типами диапазонов кода и разными типами вывода. Это не только разработано, но и реализовано в языке программирования под названием SkyLine (мой язык программирования, над которым я работаю). Обратите внимание, что все сказанное в процессе разработки относится к коду, используемому на этом языке, и будет подробно объяснено в процессе разработки.

Предпосылки

Прежде чем мы начнем, есть некоторые термины, которые мы должны знать, прежде чем мы узнаем больше о системах ошибок и прежде чем мы сами реализуем их в языке программирования.

  • REPL:Read Eval Print Loop, также известный как REPL, представляет собой консоль, которая позволяет выполнять код через интерпретатор или компилятор языка программирования построчно. Обычно они выглядят так

  • Ошибки разработчиков .Ошибки, характерные для разработчиков. Эти ошибки используются в системах, которые должны устранять или исправляться разработчиками, а не пользователем, который может исправить извне.
  • Программные ошибки.Ошибки, возникающие в программе. В данном случае мы также используем этот термин для обозначения ошибок в языке программирования, таких как синтаксические ошибки.
  • Ошибки пользователя: ошибки пользователя. Эти ошибки типа o существуют в программе, чтобы сообщить пользователю, что с программой что-то пошло не так, и в большинстве случаев это то, что они могут исправить.
  • Peek: Peek используется для определения способа «заглянуть» вперед в интерпретаторе. Например, скажем, у вас есть следующее утверждение
let x = 10 == 10; 

Этот оператор представляет собой логический результат, где x возвращает значение true, поскольку 10 равно 10. Когда проверяются определенные ключи или токены, например символ равенства, язык программирования может вызвать функцию, известную как Peek, чтобы заглянуть вперед и классифицировать этот токен как другой токен. . Это выглядит следующим образом в коде лексера.

 case '=':
  if lex.Peek() == '=' {
     character := lex.Char
     lex.Readcurchar()
     token = Tk{
      Token_Type: EQ,
      Literal:    string(ch) + string(lex.Char),
     }
  } else {
     token = newToken(ASSIGN, lex.Char)
  }

В этом утверждении в основном говорится, что если текущее значение является символом =, то продолжайте просмотр и проверку другого символа =, и если это так, то становится токеном EQ, где, если это условие не выполняется, токен становится токеном назначения, который работает, потому что есть не был вторичным символом =.

  • PrevT: Предыдущий токен. Это способ представления ранее проанализированного токена, который обычно используется в определенных операторах для проверки или подтверждения предыдущего токена перед запуском определенной функции для следующего или текущего токена.

Почему существуют системы ошибок?

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

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

Системы ошибок очень важны и присутствуют почти в каждом приложении, которое мы все используем, или в каждом языке или среде, которые мы можем использовать. Без системных ошибок приложениям было бы ужасно устранять неполадки, поскольку мы никогда не знали бы, что происходит, почему происходит сбой, почему не устанавливается соединение и т. д. и т. д.

Современная проблема с системами ошибок

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

Программатик

  • 1 → Современные системы программных ошибок стали намного лучше с момента появления языков программирования. Тем не менее, языки программирования до сих пор не имеют современных систем ошибок, поскольку разработчики этих языков называют «слишком много работы», чтобы исправить проблемы в системе ошибок. Это может привести ко многим проблемам в процессе разработки и сделать ошибку практически бесполезной в таких случаях, как java, C++ или C, которые выдают миллион ошибок, вызванных отсутствием точки с запятой или скобки. Современные языки, однако, включают определенные системы ошибок и системы трассировки, которые помогают улучшить работу с цветным выводом, системы предложений, системы перегрузки и многое другое, чтобы сделать решение этой проблемы намного лучше.
  • 2 → Вторая самая раздражающая вещь в большинстве программных систем ошибок — это синтаксис систем ошибок. Если вы новичок в языке программирования, вы можете получить сообщение об ошибке, которое использует старые формы английского языка или неправильно описывает ошибку в хорошем контексте. Это связано с тем, что системы ошибок, особенно в старых языках программирования, никогда не имели системы, основанной на контексте, что означает, что для каждой возникающей ошибки существует такое-то и такое-то количество обстоятельств, которые могут быть вызваны этой ошибкой, и способы ее исправления. В современных языках вы можете обнаружить, что это изменилось.

Пользователь

  • 1 → Как и второй пример в системах программных ошибок, этот также представлен в виде контекста и описания. Я обнаружил, что большинство современных программ с ошибками довольно легко читаются, исходя из технического фона, то есть с учетом того, что ошибка является простой ошибкой, а не чем-то сложным. Когда дело доходит до более сложных ошибок, я замечаю, что разработчики не понимают, что не все, использующие их продукт, поймут, что такое целочисленное переполнение, которое в любом случае должно быть проблемой и ошибкой разработчика. Давайте поместим это в гораздо более распространенную ситуацию, чтобы скорее сопоставить это. Если вы используете чью-то программу, такую ​​как средство проверки соединений, которое используется с графическим интерфейсом, и графический интерфейс дает сбой, и программа выдает ошибку, она просто скажет an error has occurred, а не что произошло или почему это произошло. В основном это недостаток дизайна в системах ошибок, потому что не сообщая пользователям, в чем была ошибка, или не предоставляя достаточного контекста, пользователю будет немного сложно понять это.
  • 2 → Большинство систем ошибок, основанных на пользователе, не совсем удобны для пользователя, поскольку некоторые ошибки могут быть слишком сложными для понимания пользователем, и он может быть не в состоянии получить надлежащую помощь. Возможность объяснить своим пользователям на простом примере, что пошло не так, всегда полезна и сделает UX даже во время проблем намного лучше, приятнее и плавнее.

Разработчик

  • 1 → Системы ошибок разработчиков не должны быть простыми, однако мы также живем в 2023 году, и нет причин вызывать панику в стеке и выводить ее в крошечном окне, которое выглядит так.
F-90-80      0xFFFFFFFF ??????????????????//
F-90-20      0x28173278 ?????????????????? WHERE????
F-90-10      0x28934664 %%%%%%%%%%%%%%%%%% IN L:5:C:9->TP(19) ROUTINE THREAD 40

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

  • 2 → Мы уже не в 1990 году, поэтому может быть полезно написать документацию по системе ошибок разработчиков, которая не будет тянуться все время. Я часто вижу, что в системах ошибок, основанных на разработчиках, это может быть очень запутанным и затянутым с точки зрения описания того, что делает ошибка. Разработчикам не нужно 90-страничное объяснение того, почему программа не может вместить более 5 вводов в текстовую панель, все гораздо проще.

Все эти проблемы все еще современные и все еще очень хорошо существуют, и я могу только представить, что они существуют, потому что никто не хочет проходить и вручную изменять 20 000 строк кода в форматировании системы ошибок и думать о творческих способах сделать системы ошибок намного больше сложный. В конце концов, вам лучше исправить эти 20 000 строк, чем перебирать 50 000 строк только потому, что вы не можете найти, где программа запаниковала или решила вылететь. Конечно, отладчики существуют, и они помогают, но не все пользователи и разработчики будут открывать отладчик только для того, чтобы посмотреть, что случилось с потоком, по крайней мере снова, не всегда.

Получение общего представления о том, как разработать собственную систему ошибок

Разработка собственной системы ошибок может быть чрезвычайно сложной, особенно если вы разрабатываете ее для языка программирования. В сегодняшней статье мы сосредоточимся на построении и проектировании системы ошибок для приложения, которое имеет собственный код, реализации, операторы и синтаксис. Это приложение на самом деле будет синтаксисом, основанным на языке программирования, и я объясню все, что происходит, чтобы вы могли понять его немного лучше.

Наша задача

  • Наша задача — разработать общую систему ошибок, которую можно было бы использовать во всем языке программирования как для разработчиков, так и для пользователей, использующих язык программирования во время разработки. Разработчики языка будут иметь гораздо более сложные, но простые аргументы и функции, в то время как пользователи также будут иметь свои собственные уникальные коды и системы, а также ошибки, основанные на контексте.

Кодовая система

  • Система кодов является довольно важной частью системы ошибок, кодовые или числовые системы позволяют вам организовывать и идентифицировать коды на основе их уникального идентификатора или шаблона. Для нашей текущей ситуации, учитывая, что мы создаем один для языка программирования, а другой для разработчиков и пользователей, мы можем использовать коды, которые выглядят следующим образом.
UC_00000
DC_00000

UC → UC означает код пользователя, который указывает, что причина, по которой выдается ошибка, связана с ошибкой пользователя или чем-то, что пользователь вызвал, например, пропустив точку с запятой или, возможно, даже написав совершенно другое выражение. чем тот, который нужен для языка.

DC →DC означает код разработки, который указывает на то, что в серверной части программы возникла ошибка, которую необходимо исправить разработчикам, например, отсутствующий аргумент или что-то подобное, что может вызвать панику. в программе или обратная трассировка.

Наши коды варьируются от 0 до 99999, потому что в том смысле, что нашей программе требуется очень конкретное число для каждого кода, у нас есть 99 тысяч возможных кодов, которые мы можем разработать. В нашем случае кодовая система будет настроена на увеличение на заданную величину, и каждый тип ошибки в языке, такой как синтаксический анализатор, лексер, токенизатор или среда, будет однозначно идентифицироваться в операторе ошибки. Например, мы можем сказать, что пользователь использовал 2384723467234672346782367846237846782367832467823678467823467823467824678234678 и сказал языку программирования отформатировать его как целое число, что является ошибкой пользователя и ошибкой синтаксического анализатора, которая будет результатом этого. Итак, мы можем сказать, что

UC_10010

— это код ошибки, специфичный для синтаксического анализатора, UC определяет, что это был код пользователя или пользовательская ошибка и ошибка, 1 после _ — это уникальный номер для синтаксического анализатора, а 10 — идентификатор типа ошибки в языке. Поначалу это может показаться чрезвычайно сложным, но чем больше мы углубимся в разработку системы ошибок для языка, тем больше она начнет работать. Ниже вы найдете список уникальных идентификаторов и кодов разработки для наших ситуаций, которые указывают на определенную часть языка.

UC → Коды пользователей

  • UC_1ffff : Этот код ошибки из-за 1 приведет к ошибке на основе синтаксического анализатора, любой пользовательский код, начинающийся с 1, будет означать, что синтаксический анализатор языка программирования выдает ошибку, такую ​​​​как «функция синтаксического анализа не найдена для…»
  • UC_2ffff : Этот код ошибки будет разработан для ошибок запуска, то есть всего, что происходит до того, как интерпретатор проанализирует и выполнит операторы в коде.
  • UC_3ffff : этот код ошибки, определенный с помощью 3, будет чем-то, что связано с состоянием оценки языка, что означает, что если оператор не был оценен правильно и быстро стал ошибкой, чем ошибка, начинающаяся с 3, за которой следует его уникальный идентификатор, будет только для оценщика. .
  • UC_4ffff : этот код ошибки будет определен как код ошибки для лексера или токенизатора. Если токен НЕЗАКОННЫЙ или не существует в качестве данного токена или идентификатора, появится код, начинающийся с 4. Это довольно легко понять и просто с точки зрения порядка.

DC → Коды разработчиков

Коды разработчика будут настроены так же, как и пользовательские коды, поскольку они по-прежнему будут поступать из одного и того же вывода, например, 1–4, поэтому синтаксический анализатор для лексера и токенизатора. Однако разница между пользовательскими ошибками заключается в том, что они будут направлены на разработчиков, таких как ошибка стека, ошибка паники, сигнал уничтожения из программы, застрявшие или зависшие части и т. д. и т. д. и т. д.

DC_97777 → Это единственный код, который меняется, поскольку 9 — это зарезервированное место для ошибок только для разработчиков, которые являются меньшими ошибками и не такими большими. Это означает, что разработчик мог пропустить аргумент функции или что-то еще при выводе пользовательских ошибок.

Синтаксис системы

Синтаксис системы — одна из самых важных вещей, которые вы могли бы сделать для разработки системы ошибок. Это связано с тем, что он обеспечивает основу для общих знаний и понимания как для разработчиков, так и для пользователей одновременно. Синтаксис также зависит от контекста ошибки, а контекст ошибки зависит от ситуации ошибки. Так что, в конце концов, все это имеет значение в зависимости от ситуации и типа ошибки, которую вы получаете. Например, если вы программист, использующий язык программирования, и вы пропустили точку с запятой, вы не хотите видеть следующее.

main.c:3:15: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘struct’
    3 |          struct
      |               ^~~~~~

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

main.csc 
    | error (UC_30010)
    | Line 1
    | Brick    -> allow x = function() {} 
    | Recomend -> allow x = function() {}; <- 

Error: Could not evaluate block statement further, 
missing semicolon after end of function in '}'

Это намного чище и приятнее для чтения, поскольку ему не нужно визуализировать или выводить бесполезные рекомендации или выводить то, что ожидается, позже мы можем позволить пользователю указать гораздо более подробные ошибки, которые в этом случае будут похожи на показанный вывод GCC. из программы Си. Это очень сложная программа и тип системы для написания, поскольку чем сложнее становится код, тем больше то, как интерпретатор читает строки, которые нам нужны, чтобы наша программа сканировала весь файл и находила каждую строку в файле. Итак, теперь у нас есть наш общий синтаксис, но как насчет ошибок разработчиков, таких как паника и ошибки, которые исходят от AST или серверной части парсера и вызывают сбои? Ну, конечно, в нашем случае некоторые языки просто хорошо работают с трассировкой стека и паниками, но они не всегда помогают разработчику, поэтому мы можем написать систему на бэкэнде, где на основе типа паники трассировка модуля- назад можно предположить, что может быть ошибка в таком-то файле на одну строку и такой-то столбец. Например, вместо того, чтобы читать что-то вроде этого

panic: runtime error: index out of range [9348344389] with length 0

goroutine 1 [running]:
main.main()
 /tmp/sandbox3961745395/prog.go:7 +0x1f

Program exited.

мы бы увидели что-то вроде этого

Routine (1) has recived a IOR error, ( index out of range )
|
| Line -> 7
| File -> prog.go
| Err  -> runtime based 
| Type -> fatal panic
| Rec  -> Prevent arrays from being indexed as the panic happened ( trace back from source code files ) arr[4384273482394]

Это гораздо более читаемо, и, несмотря на то, что приведенное выше также читабельно, второе отформатировано немного проще и лучше для понимания разработчиком. Общая концепция и дизайн этих сообщений об ошибках и типов на самом деле полностью связаны с объяснением. В некоторых ситуациях, таких как более глубокая паника, когда узел может выйти из строя или происходит нарушение сегмента, вам может понадобиться ГОРАЗДО более сложный отладчик на серверной части, работающий и проверяющий ошибки и панику в другом потоке, а затем сравнивающий их со статическими операторами ошибок. В некоторых случаях вы также можете обнаружить фактор, что вы просто не можете упростить ошибку, что просто имеет смысл, потому что не все ошибки разработчиков должны быть идеальными. Ниже вы найдете плохой пример системы ошибок в этом языке.

SkyLine|linux(amd64)>> io.clear()
Error system function call was not found, developer 
error ( not enough arguments in call to error map) 

Когда пользователь вызывает io.clear(), система ошибок указывает на ошибку разработчика, что означает, что в карте ошибок может быть недостаточно аргументов. Но в этой ситуации есть 20 разных карт ошибок с разными целями, которые запускаются и возвращают разные функции и типы! Итак, как мы можем сделать это лучше? Ну, в этом смысле мы можем изменить формулировку вот так.

| User C -> UC_10020
| Code   -> DC_97777
| Error  -> Dev may have forgotten the proper amount of arguments in call to 
map -> Parser_Errors which for the code given UC_10020 which translates to a 
missing function decleration code specified for functions that are missing 
definitions but are being called? Please ensure you go to this map located at 
line (3942) in module (SkyLine_ErrorSystem_Codes.go) before finishing up. If 
you are a user please report this to the developers

Да, это очень, ОЧЕНЬ длинное и подробное объяснение ошибки, которая может произойти в операторах, однако это компенсирует более приятную систему и позволяет вашим разработчикам точно указать, что они сделали неправильно и как они могут это исправить. Теперь, когда у нас есть синтаксис и идея, нам нужно обсудить некоторые ограничения систем ошибок.

Ограничения хороших систем ошибок

  • Многие разработчики создают простые скучные системы ошибок, потому что, по правде говоря, создание систем ошибок, особенно для языков программирования или ресурсоемких приложений, может занять очень много времени и, если все сделано неправильно, может привести к большему количеству ошибок, ошибочной системе ошибок или раздутому приложению. В случае с языком программирования вам нужна хорошая безопасная и надежная система ошибок без раздувания, даже если требуется более 9000 кодов, чтобы устранить все возможные ошибки и возможные паники в языке. Это накладывает ограничения на дизайн, и если разработчик языка хочет быстро подготовить язык к производству, он определенно ограничит варианты использования того, как разрабатывается система ошибок, как она выдает ошибки, рекомендует ли она исправление или просто в целом. как он отслеживает данные вокруг. Создание следующих систем требует очень много времени в больших базах кода, таких как языки программирования.
  • Трассировщики строк: их создание может быть утомительным, потому что они требуют предварительного чтения всего файла и сохранения где-то всех операторов.
  • Трассировщики столбцов: это даже сложнее, чем трассировщики строк, потому что трассировщики столбцов требуют большого количества ключевых данных для поиска и сравнения данных.
  • Выходные трассировщики: вывод трассировщика как для столбцов, так и для строк может быть очень разочаровывающим, поскольку они могут потребовать определенных математических уравнений для правильного размещения символа, такого как стрелка, указывающая на предложение, указывающее на столбец и строку ошибки в вашем коде.
  • Перегрузки. Перегрузки очень важны, но они занимают много времени и требуют постоянных знаний о том, как лучше написать или исправить ошибку во время выполнения или перед ним. У некоторых языков, таких как SkyLine, есть будущее, чтобы сделать код самовосстанавливающимся и ремонтируемым, что означает, что если вы сделаете ошибку во время выполнения, например, отсутствующую точку с запятой, или вы сделаете ошибку при вызове или импорте стандартной библиотеки, «например, math», язык программирования обратно- end error system вернется во времени до того, как это было проанализировано, и добавит оператор импорта для импорта стандартной библиотеки. Эти два типа систем чрезвычайно сложны и требуют большого количества внутренних знаний о том, как работают системы ошибок.

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

Реализация: последний шаг

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

  • Системы перегрузки
  • Трассировщики столбцов
  • Трассировщики линий

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

Точки с запятой → Почему, просто… почему

По правде говоря, точки с запятой намного легче анализировать, чем пробелы, и просто работать немного проще, чем большинство типов конечных операторов. Следующий синтаксис показывает, как мы объявляем функции на языке SkyLine.

allow x = function() {
    io.clear->io.input("input>", "expect:integer", "n")
} 

Это простая переменная, которая содержит функциональную переменную и вызывает io.clear для io.input, который очистит существующий ввод и заменит его новым значением. Теперь давайте немного рассмотрим это, мы создали здесь функцию, которая имеет несколько операторов, которые определены ниже.

1: оператор присваивания, оператор присваивания позволяет или позволяет x быть равным функции. Когда синтаксический анализатор встречает этот оператор, он ищет ключевое слово function и анализирует все, что находится внутри (). После этого он будет peek (метод просмотра заключается в проверке следующего токена после оператора, ключевого слова или другого токена, такого как оператор), чтобы убедиться, что { есть. Квадратные скобки обычно указывают на то, что функция теперь имеет активное тело. Оператор body анализируется и проходит через синтаксический анализатор и обычно находится в функции, подобной следующей.

func (parser *Parser) FCM_BlockStatement() *BlockStatement {
    block := &BS{
        T:      parser.CurrentToken,
        Stmt: []Statement{},
    }

    parser.NT()
    for !parser.CurrentTokenIs(RBRACE) && !parser.CurrentTokenIs(EOF) {
        stmt := parser.parseStatement()
        if stmt != nil {
            block.Statements = append(block.Statements, stmt)
        }

        parser.NT()
    }

    return block
}

Этот блок кода назначит токен операторов блока и тело оператора. Анализатор вызывает NT, что означает NextToken, а затем создает цикл for. Если синтаксический анализатор не встречает правую фигурную скобку или скобку, которая равна }, он продолжит синтаксический анализ. Как только обнаруживается, что он возвращает блок, в этом коде есть проблема, вы ее видите? этот код не проверяет точки с запятой, что означает, что если токен является EOF, а текущий токен является правой фигурной скобкой, продолжайте анализировать код. Это может стать проблемой в процессе разработки, особенно если разработчик забудет сказать токенизатору и лексеру, что привет! пробел считается EOF. Это может вызвать множество проблем при разработке языка программирования. Конечно, большинство языков будут основаны на пробелах, и они будут работать и обнаруживать, когда пробелы заканчиваются, однако работа только с пробелами — очень неприятная задача и порождает проблемы в будущем. Решение этой проблемы заключается в том, что большинство разработчиков добавят перед тем, как этот блок может быть возвращен, оператор, чтобы проверить, является ли текущий токен точкой с запятой. Система ошибок для проверки на наличие одной из них также является лучшей. О точках с запятой можно легко забыть, поэтому современные системы и языки программирования уничтожили их для определенных вариантов использования, однако на первых этапах разработки таких языков, как C, языку и интерпретатору может быть проще указать конец оператора.

func (parser *Parser) parseFunctionLiteral() Expression {
    l := &FunctionLiteral{T: parser.CT}
    if !parser.PEEKEXCEPTION(LPAREN) {
        return nil
    }
    l.Parameters = parser.LoadArguments()
    if !parser.PEEKEXCEPTION(LBRACE) {
        return nil
    }
    l.Body = parser.FCM_BlockStatement()
    return l
}

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

func (parser *Parser) ParseBlocks() *BStatement {
 blc := &BStatement{
  T:      parser.CurrentToken,
  Stmts: []Statement{},
 }

 parser.NT()
 for !parser.CurrentTokenIs(RBRACE) && !parser.CurrentTokenIs(EOF) {
  stmt := parser.PSTMT()
  if stmt != nil {
     block.Statements = append(block.Statements, stmt)
  }

  parser.NT()
 }
 if parser.CTis?(RBRACE) && !parser.PTIs?(SEMICOLON) {
  fmt.Println("Error: Could not evaluate block statement further, missing semicolon after end of function in '}' ")
  os.Exit(1)
 }

 return block
}

Этот код вернет ошибку, говорящую о том, что если нет точки с запятой, которую вам нужно добавить, и вы ее пропустили, это означает, что вывод выглядит примерно так.

Это еще один хороший пример плохой системы ошибок, конечно, он говорит вам, как работать с точкой с запятой и что вам не хватает, но это REPL (Read Eval Print Loop), что означает, что мы, очевидно, знаем, в какой строке мы ошиблись, и не нуждаются в дополнительных пояснениях. Но если мы выполняем программу, мы не увидим, в какой строке она допустила ошибку, без дополнительных объяснений, поэтому мы можем отредактировать этот блок кода, чтобы получить имя функции, или получить текущее имя функции, а затем вывести код для просмотра. что-то вроде этого

E | main.csc
     | Code  -> UC_30010
     | Type  -> Evaluator error (3)
     | Line  -> allow x = function(){}
     | Error -> Variable (x) assigned as a function is missing a semicolon 
|----|
Recomend -> allow x = function(){};

Это ГОРАЗДО проще для понимания и ОЧЕНЬ легко для понимания, с правильной раскраской и кодами мы действительно можем добиться того, чтобы это выглядело намного лучше, чем может показаться на первый взгляд. Это намного понятнее, чем предыдущая система ошибок, и гораздо более информативна, чем предыдущая. Подобные системы ошибок значительно упрощают чтение и улучшают работу пользователей и разработчиков. Очевидно, что эту функцию и систему можно было бы отредактировать намного больше, чтобы получить количество строк и столбцов, подобное системе кристаллических ошибок, показанной ниже.

В этом случае его также может быть легче читать, но его все еще может быть сложно добавить, поэтому какие изменения будут добавлены в код, который мы показали выше? Эта конкретная функция не будет изменена, а будет изменена вся внутренняя часть языка, чтобы получить текущую строку или значения синтаксического анализа, предыдущие и просмотренные операторы. Серверная часть системы ошибок SkyLine на данный момент довольно мала, но имеет большую систему ошибок и кодов, которая выглядит примерно так.

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

Теперь, когда у нас есть базовое понимание того, как реализуются системы ошибок, что мы можем делать дальше? Как мы пойдем дальше? Хороший вопрос!

Доведение до крайности

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

  • Кроссплатформенная поддержка. Системы ошибок могут использовать определенные цветовые коды, такие как показанный ниже, чтобы сделать определенное сообщение об ошибке более громким и заметным для разработчика или пользователя языка программирования. Однако, как объяснялось в предыдущих статьях, цветовые коды могут быть гораздо более неприятными в работе и могут быть немного более раздражающими, чем забавными. Поэтому, возможно, рассмотрите возможность написания модуля для операционных систем, таких как Windows, который будет загружать соответствующие библиотеки DLL, такие как Kernel32.DLL, для установки вывода консоли, если определенные шестнадцатеричные цветовые коды не работают.
  • Рекомендация по коду. Хорошей частью системы ошибок является система рекомендаций, которая рекомендует определенные идеи для кода на языке или рекомендует настройку с учетом набора условий, которые являются истинными. Например, мы можем создать логический шлюз, который проверяет, требуется ли включение и продолжает ли он выполнять действие, если нет, то проверяет, является ли это стандартным вызовом, и если он импортирован и не импортируется, чем предупреждает пользователя, если он импортирован и все в порядке, чем мы можем продолжать.

Т = Ложь

F = Истина

import = first conditional (это импорт на верхнем уровне): если !ok, то продолжайте предупреждать пользователя, если else, то продолжайте проверять, является ли это стандартным вызовом, если это стандартный вызов, то продолжайте, если еще, то предупреждайте. Эта графика испортилась, мои извинения. Однако это хороший пример того, как системы рекомендаций могут работать на бэкенде языков программирования, поскольку они представляют собой серию сравнений и проверок верхнего или среднего уровня до того, как программа будет полностью скомпилирована.

  • Самовосстанавливающийся код: вы слышали о системах рекомендаций для таких языков программирования, как C и C++, но как насчет самовосстанавливающегося кода? Код самовосстановления — это очень сложная концепция, в которой используется идея систем ошибок, и он может в основном реализовать внутри себя вариант использования ИИ. В основном общая идея самовосстановления кода заключается в том, что вы запускаете программу на C, как показано ниже.
int main() {
  printf("%s", "hello world");
  return 0;
}

и вы получаете предупреждение и примечание о том, что вы должны добавить это в программу, так как позже это может конфликтовать

это идея самоисцеляющегося кода, но не в полной мере. Самовосстанавливающийся код будет системой ошибок, которая слушает на бэкэнде очень специфические паники, ошибки времени выполнения, нарушения сегментов или, в случае отсутствия в языке программирования точек с запятой, отсутствующих конечных операторов, отсутствующих скобок, и фактически добавит эти скобки для пользователя. и попробуйте повторно запустить ту же программу. Эта концепция очень и очень сложна и требует глубоких знаний о возврате назад и четвертом между средами, особенно в настройке компилятора байтового кода, но эта идея того стоит. SkyLine работает над тем, как автоматически восстанавливать тела функций, автоматически восстанавливать и исправлять неработающие условные операторы, неработающие операторы switch case и другие очень важные операторы. Это позволяет языку быть немного более модульным и делает его отличным для программирования, потому что это намного упрощает работу разработчика. Подобные системы снова потребуют времени, и в зависимости от того, как они работают, они могут сделать язык лучше или хуже, что всегда зависит от разработчика на другом конце.

  • Трассировщики строки, столбца и символа: эти типы систем найдут ошибку, но напрямую отследят ее до прямой строки и столбца программы. Это работает, отслеживая каждый столбец и каждую строку кода, с которой может столкнуться синтаксический анализатор, таким образом, вы можете выполнить небольшие вычисления и отобразить строку, в которой произошла ошибка, и добавить ее к предыдущему столбцу или если ваш столбец записан раньше. ошибка, затем просто запишите номер столбца, а затем выведите его, когда ошибка будет обработана.

Что ж, это все об этом, и это всего лишь несколько систем, чтобы дать вам хорошее представление о том, куда идти дальше.

Заключение и резюме

Вау, эта статья оказалась намного длиннее, чем мы ожидали. Сначала мы говорили о том, почему существуют системы ошибок, а затем коснулись общих проблем с «современными» системами ошибок, чтобы лучше понять, как мы можем сделать современные системы ошибок намного лучше как для UX, так и для DX. Написание систем ошибок в большинстве случаев чрезвычайно сложно, особенно для более крупных проектов, таких как ваш собственный язык программирования, поскольку для этого требуется обширное исследование того, как ошибки могут быть лучше устранены, и хорошее понимание того, как может работать ваш язык и другие языки, потому что нужно смотреть и понимать, как работает код других людей. также может дать вам лучшее представление. Было очень приятно поговорить о том, как работают системы ошибок, и я надеюсь, что вы узнали что-то новое из этой статьи!

До следующего Totally_Not_A_Haxxer OUT!

Не забудьте поддержать меня на всех моих страницах в социальных сетях и основных аккаунтах!

  • Поддержите меня на гитхабе

ArkAngeL43 — Обзор

  • Поддержите меня в инстаграме

https://www.instagram.com/Totally_Not_A_Haxxer

  • Ссылки на маяки

https://www.beacons.ai/Totally_Not_A_Haxxer

  • Кассовое приложение