Оператор (компьютерное программирование)
Эта статья нуждается в дополнительных цитатах для проверки . ( январь 2019 г. ) |
В компьютерном программировании операторы — это конструкции, определенные в языках программирования , которые ведут себя как функции , но отличаются синтаксически или семантически .
Общие простые примеры включают арифметику (например, сложение с +
), сравнение (например, « больше чем » с >
) и логические операции (например , AND
, также написано &&
на некоторых языках). Более сложные примеры включают присваивание (обычно =
или :=
), доступ к полю в записи или объекте (обычно .
) и оператор разрешения области (часто ::
или .
). Языки обычно определяют набор встроенных операторов и в некоторых случаях позволяют пользователям добавлять новые значения к существующим операторам или даже определять совершенно новые операторы.
Синтаксис
[ редактировать ]Синтаксически операторы обычно противопоставляются функциям . В большинстве языков функции можно рассматривать как специальную форму префиксного оператора с фиксированным уровнем приоритета и ассоциативностью, часто с обязательными круглыми скобками , например Func(a)
(или (Func a)
в Лиспе ). Большинство языков поддерживают функции, определяемые программистом, но не могут претендовать на поддержку операторов, определяемых программистом, если только они не имеют более чем префиксной записи и более одного уровня приоритета. Семантически операторы можно рассматривать как особую форму функции с различными обозначениями вызова и ограниченным количеством параметров (обычно 1 или 2).
Положение оператора относительно его операндов может быть префиксным , инфиксным или постфиксным , а синтаксис выражения, включающего оператор, зависит от его арности (количества операндов ), приоритета и (если применимо) ассоциативности . Большинство языков программирования поддерживают бинарные операторы и несколько унарных операторов , а некоторые поддерживают больше операндов, например, оператор ?: в C, который является троичным. Существуют префиксные унарные операторы, например унарный минус. -x
и постфиксные унарные операторы, такие как постинкремент x++
; а бинарные операции являются инфиксными, например x + y
или x = y
. Инфиксные операции более высокой арности требуют дополнительных символов, таких как тернарный оператор ?: в C, записанный как a ? b : c
— действительно, поскольку это единственный распространенный пример, его часто называют тернарным оператором. Однако префиксные и постфиксные операции могут поддерживать любую желаемую арность, например 1 2 3 4 +
.
Изредка [1] [2] части языка могут быть описаны как « фиксация совпадений » или « циркумфикс ». [3] [4] операторы, чтобы упростить описание или реализацию языка. Оператор циркумфикса состоит из двух или более частей, охватывающих его операнды. Операторы Circumfix имеют наивысший приоритет: их содержимое оценивается, а полученное значение используется в окружающем выражении. Наиболее знакомым оператором циркумфикса являются упомянутые выше круглые скобки, которые используются для указания того, какие части выражения должны оцениваться раньше других. Другим примером из физики является обозначение внутреннего произведения Дирака нотации . Операторы циркумфикса особенно полезны для обозначения операций, которые включают в себя множество или различное количество операндов.
В спецификации языка будет указан синтаксис поддерживаемых им операторов, в то время как языки, такие как Пролог , которые поддерживают операторы, определяемые программистом, требуют, чтобы синтаксис был определен программистом.
Семантика
[ редактировать ]Семантика операторов особенно зависит от значения, стратегии оценки и режима передачи аргументов (например, логического короткого замыкания). Проще говоря, выражение, включающее оператор, каким-то образом вычисляется, и результирующее значение может быть просто значением (r-значение) или объектом, допускающим присваивание (l-значение).
В простых случаях это идентично обычным вызовам функций; например, дополнение x + y
обычно эквивалентно вызову функции add(x, y)
и меньше сравнения x < y
к lt(x, y)
, что означает, что аргументы оцениваются обычным способом, затем вычисляется некоторая функция и результат возвращается в виде значения. Однако семантика может существенно отличаться. Например, в задании a = b
цель a
не оценивается, а вместо этого используется его местоположение (адрес) для хранения значения b
– соответствует семантике вызова по ссылке . Кроме того, присвоение может быть оператором (без значения) или выражением (значением), причем само значение может быть либо r-значением (просто значение), либо l-значением (которому можно присвоить). В качестве другого примера — оператор разрешения области :: и оператор доступа к элементу. (как в Foo::Bar
или a.b
) оперируют не значениями, а именами , по сути, семантикой вызова по имени , и их значением является имя.
Использование l-значений в качестве операндов операторов особенно заметно в унарных операторах увеличения и уменьшения . В C, например, следующий оператор является допустимым и четко определенным и зависит от того факта, что индексация массива возвращает l-значение:
x = ++a[i];
Важным применением является ситуация, когда левоассоциативный бинарный оператор изменяет свой левый аргумент (или создает побочный эффект ), а затем вычисляет этот аргумент как l-значение. [а] Это позволяет использовать последовательность операторов, влияющих на исходный аргумент, обеспечивая свободный интерфейс , аналогичный каскадированию методов . Типичным примером является <<
оператор в C++ iostream
библиотека, которая обеспечивает свободный вывод, а именно:
cout << "Hello" << " " << "world!" << endl;
Пользовательские операторы
[ редактировать ]Язык может содержать фиксированное количество встроенных операторов (например, +, -, *, <, <=, !, = и т. д. в C и C++ , PHP ), или это может позволить создавать определяемые программистом операторы (например, Prolog , [5] Семя7 , [6] F# , OCaml , Haskell ). Некоторые языки программирования ограничивают символы оператора специальными символами, такими как + или := в то время как другие допускают также такие имена, как div
(например, Паскаль ).
Большинство языков имеют встроенный набор операторов, но не допускают операторов, определяемых пользователем, поскольку это существенно усложняет синтаксический анализ. [б] Многие языки позволяют использовать операторы только для встроенных типов, но другие позволяют использовать существующие операторы для пользовательских типов; это известно как перегрузка операторов . Однако некоторые языки позволяют определять новые операторы либо во время компиляции, либо во время выполнения. Это может включать метапрограммирование (определение операторов на отдельном языке) или внутри самого языка. Определение новых операторов, особенно определение во время выполнения, часто делает невозможным правильный статический анализ программ, поскольку синтаксис языка может быть полным по Тьюрингу, поэтому даже построение синтаксического дерева может потребовать решения проблемы остановки, что невозможно. Это происходит с Perl , например, и некоторыми диалектами Lisp .
Примеры
[ редактировать ]Типичными примерами синтаксических различий являются математические арифметические операции , например «>» для « больше чем языка », с именами, часто выходящими за пределы набора идентификаторов для функций, и вызываемые с синтаксисом, отличным от синтаксиса языка для вызова функций. Как функция, «больше» обычно обозначается идентификатором, например gt
или greater_than
и вызывается как функция, как gt(x, y)
. Вместо этого операция использует специальный символ >
(который токенизируется отдельно во время лексического анализа ) и инфиксную нотацию, например x > y
.
Распространенными примерами, которые отличаются семантически (по режиму передачи аргументов), являются логические операции, которые часто содержат короткую оценку : например, короткая конъюнктура (X И Y), которая оценивает более поздние аргументы только в том случае, если более ранние не являются ложными, в языке с строгие функции вызова по значению. Вместо этого это ведет себя аналогично if/then/else.
Менее распространенные операторы включают:
- Оператор запятая :
e, f
- Оператор разыменования :
*p
и адрес-оператора:&x
- ?: или тернарный оператор:
number = spell_out_numbers ? "forty-two" : 42
- Оператор Элвиса :
x ?: y
- Оператор Элвиса :
- Нулевой оператор объединения :
x ?? y
- Оператор космического корабля (для трехстороннего сравнения ):
x <=> y
- Составные операторы, объединяющие две или более атомарные операции в одну, чтобы упростить выражения , облегчить оптимизацию компилятора в зависимости от базовой аппаратной реализации или повысить производительность за счет скорости или размера. Примером может служить набор составных операторов присваивания (также известных как расширенное присваивание) в C/C++:
+=
,-=
,*=
,/=
,%=
,<<=
,>>=
,&=
,^=
,|=
Аналогичным образом, некоторые процессоры цифровых сигналов предоставляют специальные коды операций для объединенных операций, таких как умножение-накопление (MAC/MAD) или объединенное умножение-сложение (FMA), а некоторые высокопроизводительные программные библиотеки поддерживают такие функции, как cis x = cos x + i sin x для повышения скорость обработки или уменьшить размер кода.
Сборник
[ редактировать ]Компилятор может реализовывать операторы и функции с помощью вызовов подпрограмм или встроенного кода . Некоторые встроенные операторы, поддерживаемые языком, имеют прямое отображение на небольшое количество инструкций, обычно встречающихся в центральных процессорах , хотя другие ( например, '+', используемый для выражения конкатенации строк ), могут иметь сложную реализацию.
Перегрузка оператора
[ редактировать ]В некоторых языках программирования оператор может быть специальным полиморфным , то есть иметь определения для более чем одного типа данных (например, в Java, где +
используется как для сложения чисел, так и для объединения строк). Такой оператор называется перегруженным . В языках, которые поддерживают перегрузку операторов программистом (например, C++ ), но имеют ограниченный набор операторов, перегрузка операторов часто используется для определения индивидуального использования операторов.
В примере IF ORDER_DATE > "12/31/2011" AND ORDER_DATE < "01/01/2013" THEN CONTINUE ELSE STOP
, операторы: >
(больше чем), AND
и <
(меньше, чем).
Приведение операндов
[ редактировать ] операнды оператора Некоторые языки также позволяют неявно преобразовывать или приводить к подходящим типам данных для выполнения операции. Например, в Perl правила приведения приводят к 12 + "3.14"
производя результат 15.14
. Текст "3.14"
преобразуется в число 3,14, прежде чем можно будет выполнить сложение. Дальше, 12
является целым числом и 3.14
является числом с плавающей запятой или числом с фиксированной запятой (число, в котором есть десятичный знак), поэтому целое число затем преобразуется в число с плавающей запятой или число с фиксированной запятой соответственно.
JavaScript следует противоположным правилам: найдя то же самое выражение, что и выше, он преобразует целое число 12
в строку "12"
, затем объедините два операнда, чтобы сформировать "123.14"
.
При наличии приведения в языке программист должен знать конкретные правила, касающиеся типов операндов и типа результата операции, чтобы избежать тонких ошибок программирования.
Возможности оператора в языках программирования
[ редактировать ]В следующей таблице показаны функции оператора на нескольких языках программирования:
Язык программирования | Небуквенно-цифровые символы операторов | Буквенно-цифровые символы операторов | Префикс | Инфикс | Постфикс | Приоритет | Ассоциативность | Перегрузка
|
Определяется программистом
перегрузка |
Определяется программистом
символы оператора |
---|---|---|---|---|---|---|---|---|---|---|
АЛГОЛ 68 | +* ** * / % %* %× - + < <= >= > = /= & -:= +:= *:= /:= %:= %*:= +=: :=: :/ =:
(Все операторы имеют жирные буквенно-цифровые эквиваленты, см. следующий столбец. Некоторые имеют эквиваленты, отличные от ASCII , см. ниже.) ¬ +× ⊥ ↑ ↓ ⌊ ⌈ × ÷ ÷× ÷* □ ≤ ≥ ≠ ∧ ∨ ×:= ÷:= ÷×:= ÷*:= %×:= :≠: |
not abs arg bin entier leng level нечетное повторение round shorten i shl shr up down lwb upb lt le ge gt eq ne и или over mod elem minusab plusab timesab divab overab modab plusto isnt | Да | Да | Нет | Да (префиксные операторы всегда имеют приоритет 10) | Инфиксные операторы левоассоциативны, префиксные операторы правоассоциативны. | Да | Да | Да |
АПЛ | + - × ÷ ⌈ ⌊ * ⍟ | ! ○ ~ ∨ ∧ ⍱ ⍲ < ≤ = ≥ > ≠ . @ ≡ ≢ ⍴ , ⍪ ⍳ ↑ ↓ ? ⍒ ⍋ ⍉ ⌽ ⊖ ∊ ⊥ ⊤ ⍎ ⍕ ⌹ ⊂ ⊃ ∪ ∩ ⍷ ⌷ ∘ → ← / ⌿ \ ⍀ ¨ ⍣ & ⍨ ⌶ ⊆ ⊣ ⊢ ⍠ ⍤ ⌸ ⌺ ⍸ | Буквенно-цифровые символы нуждаются в ⎕ перед ключевым словом. | Да (только функции первого порядка) | Да | Да (только функции высшего порядка) | Функции высшего порядка предшествуют функциям первого порядка. | Функции высшего порядка левоассоциативны, функции первого порядка правоассоциативны. | Да | Да | Да (только буквенно-цифровой) |
Б | () [] ! ~ ++ -- + - * & / % << >> < <= > >= == != ^ | ?: = =+ =- =* =/ =% =& =^ =| [7] | Да | Да | Да | Да | Да | Да | Нет | Нет | |
С | () [] -> . ! ~ ++ -- + - * & / % << >> < <= > >= == != ^ | && || ?: = += -= *= /= %= &= ^= | размер | Да | Да | Да | Да | Да | Да | Нет | Нет |
С++ ( подробнее ) | sizeof typeid new delete throw decltype static_cast динамическое приведение reinterpret_cast const_cast | Да | Да | Да | Да | Да | Да | Да | Нет | |
С# ( подробнее ) | То же, что C/C++, но с ?. ?[] ?? ??= | sizeof имя нового стекаalloc await throw отмечено не отмечено, как делегат по умолчанию true false ЛИНК : из выберите где группа... по группе... по... в объединение... в... по... равно объединение... в... по... равно... в порядок по порядку. ...по убыванию Рослин : Только __makeref __refvalue __reftype |
Да | Да | Да | Да | Да | Да | Да | Нет |
Ява | То же, что C/С++ | новый броска экземпляр экземпляра | Да | Да | Да | Да | Да | Да | Нет | Нет |
Эйфелева | [] + - * / // = /= | не и или подразумевает «и тогда» «или иначе» | Да | Да | Нет | Да | Да | Нет | Да | Да |
Хаскелл | + - * / ^ ^^ ** == /= > < >= <= && || >= >> $ $! . ++ !! : Еще много в обычных библиотеках. | Имя функции должно быть заключено в обратные кавычки. | Да | Да | Нет | Да | Да | Да, используя классы типов | Да | |
Паскаль | * / + - = < > <> <= >= := | не div mod и /или в | Да | Да | Нет | Да | Да | Да | Нет | Нет |
Перл | -> ++ -- ** ! ~ \ + - . =~ !~ * / % < > <= >= == != <=> ~~ & | ^ && || ' | распечатать сортировку chmod chdir rand и или нет xor lt gt le ge eq ne cmp x | Да | Да | Да | Да | Да | Да | Да | Нет |
PHP | [] ** ++ -- ~ @! [8] * / % + - . << >> < <= > >= == != === !== <> <=> & ^ | && || ?? ?: = += -= *= **= /= .= %= &= |= ^= <<= >>= | клонировать новую неустановленную печать echo isset instanceof и /или xor | Да | Да | Да | Да | Да | Нет | Нет | Нет |
ПЛ/Я | ( ) -> + - * / ** > ¬> >= = ¬= <= < ¬< ¬ & | || | Да | Да | Нет | Да | Да | Нет | Нет | Нет | |
Пролог | :- ?- ; , . =.. = \= < =< >= > == \== - + / * | spy nospy не является модом | Да | Да | Да | Да | Да | Нет | Нет | Да |
Раку | ++ -- ** ! ~ ~~ * / + - . < > <= >= == != <=> & | ^ && || // [9] | распечатать сортировку chmod chdir rand и или нет xor lt gt le ge eq ne leg cmp x xx | Да | Да | Да | Да | Да | Да | Да | Да [10] |
Сид7 | {} [] -> ** ! + - * / << >> & >< | = <> > >= < <= <& := +:= -:= *:= /:= <<:= >>:= &:= @:= | conv varConv синтаксический анализ conj div rem mdiv mod times multi not и /или цифры lpad rpad lpad0 | Да | Да | Да | Да | Да | Да | Да | Да |
Смолток | (да - до двух символов [11] ) | Буквенно-цифровые символы требуют двоеточия после ключевого слова. | Нет | Да | Да | Нет | Нет | Да | Да | Да |
Быстрый | Любая строка символов Юникода, кроме . , включая ! ~ + - * / % =+ =- =* =/ =% &+ &- &* =&+ =&- =&* && || << >> & | ^ == != < <= > >= ?? ... ..< в стандартной библиотеке | это как? | Да | Да | Да | Да (определяется как частичный порядок в группах приоритета) | Да (определяется как часть групп приоритета) | Да | Да | Да |
Визуальный Бейсик .NET | () . ! ?() ?. ?! + - * / \ & << >> < <= > >= ^ <> = += -= *= /= \= &= ^= <<= >>= | Новый мод Await Like Is IsNot Not And AndAlso Or OrElse Xor If(...,...) If(...,...,...) GetXmlNamespace(...) GetType(...) NameOf( ...) TypeOf...Is TypeOf...IsNot DirectCast(...,...) TryCast(...,...) CType(...,...) CBool(...) CByte(...) CChar(...) CDate(...) CDec(...) CDbl(...) CInt(...) CLng(...) CObj(...) CSByte( ...) CShort(...) CSng(...) CStr(...) CUInt(...) CULng(...) CUShort(...) ЛИНК : From Aggregate...Into Select Distinct Где <Упорядочить по>...[По возрастанию|По убыванию] Take <Take While> Пропустить <Skip While> Let Group...By...Into Join...On <Group Join. ..В...В> |
Да | Да | Да | Да | Да | Да | Да | Нет |
См. также
[ редактировать ]Примечания
[ редактировать ]- ^ И наоборот, правоассоциативный оператор с правым аргументом, хотя это встречается реже.
- ^ Введение нового оператора меняет лексическую спецификацию языка, что меняет лексический анализ . Арность и приоритет оператора тогда являются частью синтаксиса фразы языка, что меняет анализ на уровне фраз. Например, добавив оператор
@
требует лексизации и токенизации этого символа, а структура фразы (синтаксическое дерево) зависит от арности и приоритета этого оператора.
Ссылки
[ редактировать ]- ^ «Формы ввода оператора — документация Wolfram Language» . ссылка.wolfram.com .
- ^ «Максима 5.42.0 Руководство: 7. Операторы» . maxima.sourceforge.net .
- ^ «Префиксные, постфиксные и циркумфиксные операторы» . сайт myryl.org .
- ^ «Операторы» . doc.perl6.org .
- ^ "SWI-Пролог -- оп/3" . www.swi-prolog.org .
- ^ «Объявить оператор» . seed7.sourceforge.net .
- ^ «УЧЕБНОЕ ВВЕДЕНИЕ В ЯЗЫК Б» .
- ^ «PHP: Операторы контроля ошибок — Руководство» . php.net .
- ^ «Операторы» . docs.perl6.org .
- ^ «Функции» . docs.perl6.org .
- ^ Гольдберг, Адель. «Smalltalk-80: язык и его реализация, стр. 27, ISBN 0-201-11371-6» (PDF) .