Лексика
Программы на обоих рассматриваемых языках, C# и Java, могут быть написаны с использованием набора символов Unicode, каждый символ в котором представляется при помощи 16-ти бит. Поскольку последние версии стандарта Unicode [10] определяют более широкое множество символов, включая символы от U+10000 до U+10FFFF (т.е. имеющие коды от 216 до 220+216–1), такие символы представляются в кодировке UTF-16, т.е. двумя 16-битными символами, первый в интервале U+D800–U+DBFF, второй — в интервале U+DC00–U+DFFF.
Лексически программы состоят из разделителей строк (символы возврата каретки, перевода строки или их комбинация), комментариев, пустых символов (пробелы и табуляции), идентификаторов, ключевых слов, литералов, операторов и разделительных символов.
В обоих языках можно использовать как однострочный комментарий, начинающийся с символов // и продолжающийся до конца строки, так и выделительный, открывающийся символами /* и заканчивающийся при помощи */.
Идентификаторы должны начинаться с буквы (символа, который считается буквой в Unicode, или символа _) и продолжаться буквами или цифрами. В качестве символа идентификатора может использоваться последовательность \uxxxx, где x — символы 0-9, a-f или A-F, обозначающая символ Unicode c шестнадцатеричным кодом xxxx. Корректными идентификаторами являются, например, myIdentifier123, идентификатор765 (если последние два представлены в Unicode). Ключевые слова устроены также (без возможности использовать Unicode-последовательности в C#), но используются для построения деклараций, инструкций и выражений языка или для обозначения специальных констант.
В Java ключевые слова не могут использоваться в качестве идентификаторов. |
Добавив в начало ключевого слова символ @, в C# можно получить идентификатор, посимвольно совпадающий с этим ключевым словом. Этот механизм используется для обращения к элементам библиотек .NET, написанным на других языках, в которых могут использоваться такие идентификаторы — @class, @int, @public и пр. Можно получать идентификаторы, добавляя @ и в начало идентификатора, но делать это не рекомендуется стандартом языка. Другой способ получить идентификатор, совпадающий по символам с ключевым словом, — использовать в нем Unicode-последовательность вместо соответствующего символа ASCII. Кроме того, в C# есть специальные идентификаторы, которые только в некотором контексте используются в качестве ключевых слов. Таковы add, alias, get, global, partial, remove, set, value, where, yield. |
В обоих языках имеется литерал null для обозначения пустой ссылки на объект, булевские литералы true и false, символьные и строковые литералы, целочисленные литералы и литералы, представляющие числа с плавающей точкой.
Символьный литерал, обозначающий отдельный символ, представляется как этот символ, заключенный в одинарные кавычки (или апострофы). Так, например, можно представить символы 'a', '#', 'Ы'. Чтобы представить символы одинарной кавычки, обратного слэша и некоторые другие, используются так называемые ESC-последовательности, начинающиеся с обратного слэша — '\'' (одинарная кавычка), '\\' (обратный слэш), '\"' (обычная кавычка), '\n' (перевод строки), '\r' (возврат каретки), '\t' (табуляция). Внутри одинарных кавычек можно использовать и Unicode-последовательности, но осторожно — если попытаться представить так, например, символ перевода строки \u000a, то, поскольку такие последовательности заменяются соответствующими символами в самом начале лексич еского анализа, кавычки будут раздел ены переводом строки, что вызовет ошибку.
В Java можно строить символьные литералы в виде восьмеричных ESC-последовательностей из не более чем трех цифр — '\010', '\142', '\377'. Такая последовательность может представлять только символы из интервала U+0000–U+00FF. | В C# можно использовать шестнадцатеричные ESC-последовательности из не более чем четырех цифр для построения символьных литералов. Такая последовательность обозначает Unicode-символ с соответствующим кодом. |
В C# можно строить буквальные строковые литералы (verbatim string literals), в которых ESC-последовательности и Unicode-последовательности не преобразуются в их значения. Для этого нужно перед открывающей кавычкой поставить знак @. В такой строке могут встречаться любые символы, кроме ". Чтобы поместить туда и кавычку, надо повторить ее два раза. Например, "Hello \t world" отличается от @"Hello \t world", а "\"" совпадает с @"""". |
Целочисленные литералы представляют собой последовательности цифр, быть может, со знаком — 1234, -7654. Имеются обычные десятичные литералы и шестнадцатеричные, начинающиеся с 0x или 0X. По умолчанию целочисленные литералы относятся к типу int. Целочисленные литералы, имеющие тип длинного целого числа long, оканчиваются на букву l или L.
В Java имеются также восьмеричные целочисленные литералы, которые начинаются с цифры 0. | В C#, в отличие от Java, имеются беззнаковые целочисленные типы uint и ulong. Литералы этих типов оканчиваются на буквы u или U, и на любую комбинацию букв u/U и l/L, соответственно. |
В Java литералы с плавающей точкой могут иметь шестнадцатеричное представление с двоичной экспонентой. При этом литерал начинается с 0x или 0X, экспонента должна быть обязательно и должна начинаться с буквы p или P. | В C# есть тип с плавающей точкой decimal для более точного представления чисел при финансовых расчетах. Литералы этого типа оканчиваются на букву m или M. |
( ) { } [ ] ; , . : ? ~ = < > ! + - * / % & | ^ == <= >= != += -= *= /= %= &= |= ^= && || ++ -- << >> <<= >>=
Дополнительные операторы Java: >>> >>>= | Дополнительные операторы C#: -> :: ?? В C#, помимо ранее перечисленных лексических конструкций, имеются директивы препроцессора, служащие для управления компиляцией. Директивы препроцессора не могут находиться внутри кавычек, начинаются со знака # и пишутся в отдельной строке, эта же строка может заканчиваться комментарием. Директивы #define и #undef служат для того, чтобы определять и удалять опции для условной компиляции (такая опция может быть произвольным идентификатором, отличным от true и false). Директивы #if, #elif, #else и #endif служат для того, чтобы вставлять в код и выбрасывать из него некоторые части в зависимости от декларированных с помощью предыдущих директив опций. В качестве условий, проверяемых директивами #if и #elif, могут использоваться выражения, составленные из опций и констант true и false при помощи скобок и операций &&, ||, ==, !=. Например using System; #define Debug public class Assert { public void Assert (bool x) { #if Debug if(!x) throw new Exception("Assert failed"); #endif } } Директивы #error и #warning служат для генерации сообщений об ошибках и предупреждениях, аналогичных таким же сообщениям об ошибках компиляции. В качестве сообщения выдается весь текст, следующий в строке за такой директивой. Директива #line служит для управления механизмом сообщений об ошибках с учетом строк. Вслед за такой директивой в той же строке может следовать число, число и имя файла в кавычках или слово default. В первом случае компилятор считает, что строка, следующая после строки с этой директивой, имеет указанный номер, во втором — помимо номера строки в сообщениях изменяется имя файла, в третьем компилятор переключается в режим по умолчанию, забывая об измененных номерах строк. Директива #pragma warning, добавленная в C# 2.0, служит для включения или отключения предупреждений определенного вида при компиляции. Она используется в виде #pragma warning disable n_1, …, n_k #pragma warning restore n_1, …, n_k где n_1, … , n_k — номера отключаемых/ включаемых предупреждений. |