Страницы

Поиск по вопросам

воскресенье, 22 декабря 2019 г.

Инкременты и сложения

#java #синтаксис


Вот такой код компилируется в Java без ошибок:

public class Test {
    public static void main(String[] args) {
        int a = 2, b = 3;
        System.out.println(a+++--b);
        System.out.println(a++-++b);
        System.out.println(a---++b);
        System.out.println(a--+--b);
    }
}


А вот тут ни одна строчка с println не компилируется:

public class Test {
    public static void main(String[] args) {
        int a = 2, b = 3;
        System.out.println(a--+++b); // error: unexpected type
        System.out.println(a++---b); // error: unexpected type
        System.out.println(a+++++b); // error: unexpected type
        System.out.println(a-----b); // error: unexpected type
    }
}


Почему так? Ну может последние две ещё сильно сложно разобрать, но первые-то почти
такие же как в работающем примере?
    


Ответы

Ответ 1



Думаю, проблема вот в чём. Компилятор Java сначала разбивает текст на токены (лексический анализ), а потом пытается понять его значение (синтаксический). Судя по всему, разбиение происходит строго слева направо. При этом ++, --, + и - являются отдельными токенами. При чтении первого примера происходит следующее разбиение: a+++--b => a ++ + -- b (поскольку после токена ++ самым длинным возможным токеном является лишь +). Это интерпретируется как (a++) + (--b). Для неработающего случая происходит следующее разбиение: a--+++b => a -- ++ + b — а это невозможно сгруппировать в валидный синтаксис, так как и слева, и справа от ++ находятся выражения, не являющиеся Java-аналогом lvalue. Подтверждение из JLS: A translation of the stream of input characters and line terminators resulting from step 2 into a sequence of input elements (§3.5) which, after white space (§3.6) and comments (§3.7) are discarded, comprise the tokens (§3.5) that are the terminal symbols of the syntactic grammar (§2.3). The longest possible translation is used at each step, even if the result does not ultimately make a correct program while another lexical translation would. Ниже в документации расположен как раз подходящий пример: The input characters a--b are tokenized (§3.5) as a, --, b, which is not part of any grammatically correct program, even though the tokenization a, -, -, b could be part of a grammatically correct program. Перевод (мой): Преобразование потока входных символов и символов окончания строки, получившегося на шаге 2, в последовательность входных элементов(§3.5), которые, после удаления пробелов (§3.6) и комментариев (§3.7), формируют токены (§3.5), являющиеся терминальными символами грамматики языка (§2.3). На каждом шаге выбирается самое длинный возможный токен, даже если результат в конечном итоге не будет корректной программой, хотя бы даже при другом разбиении на токены получилась корректная программа. Входные символы a--b разбиваются на токены (§3.5) как a, --, b, что не является частью синтаксически корректной программы, хотя разбиение a, -, -, b могло бы быть таковым.

Комментариев нет:

Отправить комментарий