Синтаксические ошибки в программировании

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

Синтаксис языка определяет его поверхностную форму.[1]Текстовые компьютерные языки основаны на последовательностях символов, в то время как визуальные языки программирования основаны на пространственном расположении и связях между символами (которые могут быть текстовыми или графическими). Говорят, что документы. Которые синтаксически недействительны, имеют

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

Синтаксис, следовательно. Относится к форме кода и противопоставляется семантикесмыслу. При обработке компьютерных языков семантическая обработка обычно идет после синтаксической обработки; однако в некоторых случаях семантическая обработка необходима для полного синтаксического анализа. И они выполняются вместе или

одновременно. В компиляторесинтаксический анализ включает в себя интерфейс, в то время как семантический анализ включает в себя бэкэнд (и средний конец. Если эта фаза различается).

Уровни синтаксиса

Синтаксис компьютерного языка обычно разделяется на три уровня:

  • Слова – лексический уровень. Определяющий. Как символы формируют лексемы;
  • Фразы – грамматический уровень. Узко говоря. Определяющий. Как лексемы формируют фразы;
  • Контекст – определение того. К каким объектам или переменным относятся имена. Допустимы ли типы и т. Д.

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

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

Даже в этих случаях синтаксический анализ часто рассматривается как аппроксимация этой идеальной модели.

Сама стадия синтаксического анализа может быть разделена на две части: дерево синтаксическогоанализа . Или абстрактное синтаксическое дерево (AST). Которое упрощает это в пригодную для использования форму. Этапы АСТ и контекстуального анализа можно рассматривать как форму семантического анализа. Поскольку они добавляют смысл и интерпретацию к синтаксису. Или же как неформальные. Ручные реализации синтаксических правил. Которые было бы трудно или неудобно описать или реализовать формально.

Уровни обычно соответствуют уровням в иерархии Хомского. Слова находятся в регулярном языке, указанном в лексической грамматике, которая является грамматикой типа 3, обычно заданной как регулярные выражения. Фразы находятся в контекстно-свободном языке (CFL), обычно детерминированном контекстно-свободном языке (DCFL), заданном в грамматике структуры фразы, которая является грамматикой типа 2, обычно заданной как производственные правила в форме Бэкуса–Наура (BNF). Грамматики фраз часто задаются в гораздо более ограниченных грамматиках , чем полные

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

Были написаны инструменты . Которые автоматически генерируют лексер из лексической спецификации. Написанной в регулярных выражениях. И парсер из грамматики фраз. Написанной в BNF: это позволяет использовать декларативное программирование, а не процедурное или функциональное программирование. Примечательным примером является пара lexyacc. Они автоматически создают конкретное синтаксическое дерево; затем автор парсера должен вручную написать код. Описывающий. Как это преобразуется в абстрактное синтаксическое дерево. Контекстуальный анализ также обычно выполняется вручную.

Несмотря на существование этих автоматических инструментов. Синтаксический анализ часто выполняется вручную по разным причинам – возможно. Структура фразы не является контекстно-свободной. Или альтернативная реализация улучшает производительность или отчеты об ошибках. Или позволяет легче изменять грамматику. Парсеры часто пишутся на функциональных языках. Таких как Haskell, или на языках сценариев. Таких как Python или Perl, или на C или C++.

Примеры ошибок

В качестве примера (add 1 1)можно привести синтаксически допустимую программу Lisp (при условии. Что функция ‘add’ существует. Иначе разрешение имен не удается). Добавляющую 1 и 1.

Однако следующие положения являются недействительными:

(_ 1 1) лексическая ошибка: '_' недопустимо (добавить 1 1 ошибка синтаксического анализа: отсутствует закрытие ')' 

Обратите внимание. Что лексер не может идентифицировать первую ошибку – все. Что он знает, это то. Что после создания токена LEFT_PAREN ‘(‘ остальная часть программы недействительна. Так как ни одно правило слова не начинается с ‘_’. Вторая ошибка обнаруживается на этапе синтаксического анализа: синтаксический анализатор идентифицировал правило производства

неоднозначным.

Ошибки типа и необъявленные ошибки переменных иногда считаются синтаксическими ошибками. Когда они обнаруживаются во время компиляции (что обычно происходит при компиляции строго типизированных языков). Хотя обычно такие ошибки классифицируются как семантические ошибки.[3][4][5]

В качестве примера можно привести код Python

'a' + 1 

содержит ошибку типа. Поскольку добавляет строковый литерал к целочисленному литералу. Ошибки типа такого рода могут быть обнаружены во время компиляции: они могут быть обнаружены во время синтаксического анализа (анализа фраз). Если компилятор использует отдельные правила. Разрешающие

В некоторых случаях эта проверка не выполняется компилятором. И эти ошибки обнаруживаются только во время выполнения.

В динамически типизированном языке. Где тип может быть определен только во время выполнения. Многие ошибки типа могут быть обнаружены только во время выполнения. Например, код Python

a + b 

синтаксически допустимо на уровне фразы. Но правильность типов a и b может быть определена только во время выполнения. Так как переменные не имеют типов в Python. А только значения. В то время как существуют разногласия относительно того. Следует ли называть ошибку типа. Обнаруженную компилятором. Синтаксической ошибкой (а не

статической семантической ошибкой). Ошибки типа. Которые могут быть обнаружены только во время выполнения программы. Всегда рассматриваются как семантические. А не синтаксические ошибки.

Определение синтаксиса

Синтаксис текстовых языков программирования обычно определяется с помощью комбинации регулярных выражений (для лексической структуры) и формы Бэкуса–Наура (для грамматической структуры) для индуктивного задания синтаксических категорий (нетерминалов) и терминальных символов. Синтаксические категории определяются правилами . Называемыми производствами, которые задают значения . Принадлежащие определенной синтаксической категории.[1] Терминальные символы-это конкретные символы или строки символов (например , ключевые слова. Такие как define, if, letили void), из которых строятся синтаксически корректные программы.

Язык может иметь различные эквивалентные грамматики. Такие как эквивалентные регулярные выражения (на лексическом уровне) или различные правила фраз. Которые генерируют один и тот же язык.

Использование более широкой категории грамматик. Таких как грамматики LR. Может позволить более короткие или простые грамматики по сравнению с более ограниченными категориями. Такими как грамматики LL. Которые могут потребовать более длинных грамматик с большим количеством правил.

Разные, но эквивалентные грамматики фраз дают разные деревья синтаксического анализа. Хотя базовый язык (набор допустимых документов) один и тот же.

Пример: Lisp S-выражения

Ниже приведена простая грамматика. Определенная с использованием нотации регулярных выражений и расширенной формы Бэкуса–Наура. Он описывает синтаксис S-выражений, синтаксис данных языка программирования

Lisp, который определяет продукты для синтаксических категорий expression, atom, number, symbolи list:

выражение = атом | список атома = число | символ  числа = [+-]?['0'-'9']+ символ = ['а'-'я']['А'--'9'].* список = '(', выражение*, ')' 

Эта грамматика определяет следующее:

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

    выражений внутри.

Здесь десятичные цифры. Символы верхнего и нижнего регистра и круглые скобки являются терминальными символами.

Ниже приведены примеры хорошо сформированных последовательностей лексем в этой грамматике: », ‘12345‘, ‘()(A B C232 (1))

Сложные грамматики

Грамматика, необходимая для определения языка программирования. Может быть классифицирована по его положению в иерархии Хомского. Грамматика фраз большинства языков программирования может быть задана с помощью грамматики типа 2, то есть они являются контекстно-свободными грамматиками

[6], хотя общий синтаксис контекстно-зависим (из-за объявлений переменных и вложенных областей). Следовательно. Тип 1. Однако есть исключения. И для некоторых языков грамматика фразы имеет тип-0 (Turing-complete).

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

неразрешимой проблемой в этих языках. А это означает. Что фаза синтаксического анализа может не завершиться. Например, в Perl можно выполнить код во время синтаксического анализа с помощью BEGIN прототипы операторов и функций Perl могут изменить синтаксическую интерпретацию и, возможно. Даже синтаксическую валидность оставшегося кода.[7] В разговорной речи это называется Аналогично, макросы Lisp, введенные defmacro синтаксис также выполняется во время синтаксического анализа. Что означает. Что компилятор Lisp должен иметь всю систему выполнения Lisp. В отличие от этого. Макросы C являются просто заменой строк и не требуют выполнения кода.

[8][9]

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

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

В некоторых случаях такие программы могут проявлять неопределенное поведение. Даже если программа четко определена в рамках языка. Она все равно может иметь значение. Которое не предназначено человеком. Который ее написал.

Используя естественный язык в качестве примера. Может оказаться невозможным придать смысл грамматически правильному предложению или оно может быть ложным:

Следующий фрагмент языка Си синтаксически корректен. Но выполняет операцию . Которая не определена семантически (поскольку p является нулевым указателем, операции p->real> и p->im> не имеют никакого значения):

 complex *p = NULL; complex abs_p = sqrt (preal * preal + pim * pim); 

В качестве более простого примера,

 int x; printf(, x); 

является синтаксически допустимым. Но не семантически определенным. Поскольку использует неинициализированную переменную. Даже если компиляторы для некоторых языков программирования (например. Java и C#) обнаруживают ошибки неинициализированных переменных такого рода. Их следует рассматривать как семантические ошибки. А не синтаксические.[5][10]

См. также

Чтобы быстро сравнить синтаксис различных языков программирования. Взгляните на список

примеров программ :

Внешние ссылки

  • Различные синтаксические конструкции. Используемые в языках программирования
  • Ошибка Python “ImportError: Нет модуля с именем” Почему? Как? Командная строка? [Solved2021]