it-swarm.com.ru

Что делает Java более простым для анализа, чем C?

Я знаком с тем фактом, что грамматики C и C++ являются контекстно-зависимыми , и, в частности, вам нужен "хак лексера" в C. С другой стороны, у меня сложилось впечатление что вы можете анализировать Java только с двумя жетонами предварительного просмотра, несмотря на значительное сходство между этими двумя языками.

Что бы вы хотели изменить в C, чтобы сделать его более удобным для анализа?

Я спрашиваю, потому что все примеры, которые я видел о чувствительности контекста C, технически допустимы, но ужасно странны. Например,

foo (a);

может вызывать функцию void foo с аргументом a. Или это может быть объявление a как объекта типа foo, но вы также можете легко избавиться от паразитов. Отчасти эта странность возникает из-за того, что производственное правило "прямого декларатора" для C грамматика выполняет двойную цель объявления как функций, так и переменных.

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

foo a;

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

Я видел, что сказано, что C трудно анализировать из-за typedef, но вы также можете объявить свои собственные типы в Java. Какие правила грамматики C, кроме direct_declarator, являются ошибочными?

89
korrok

Парсинг C++ становится сложным. Синтаксический анализ Java становится таким же сложным.

Смотрите это ТАК ответ, обсуждающий, почему C (и C++) "трудно" анализировать . Краткое резюме заключается в том, что грамматики C и C++ по своей сути неоднозначны; они дадут вам несколько разборов, и вы должны использовать контекст для устранения неоднозначностей. Люди тогда делают ошибку, предполагая, что вы должны разрешить неясности при разборе; не так, см. ниже. Если вы настаиваете на разрешении двусмысленностей во время разбора, ваш парсер становится более сложным и его гораздо сложнее построить; но эта сложность является нанесенной самим себе раной.

IIRC, Java "очевидная" грамматика LALR (1) 1.4 не была неоднозначной, поэтому ее было "легко" проанализировать. Я не уверен, что у современного Java нет по крайней мере локальных неоднозначностей; всегда есть проблема определения, закрывает ли "... >>" два шаблона или "оператор сдвига вправо". Я подозреваю современная Java больше не разбирает LALR (1) .

Но можно обойти проблему синтаксического анализа, используя сильные парсеры (или слабые парсеры и хаки для сбора контекста, как это обычно делают интерфейсы C и C++) для обоих языков. C и C++ имеют дополнительное усложнение наличия препроцессора; на практике это сложнее, чем кажется. Одно утверждение состоит в том, что синтаксические анализаторы C и C++ настолько сложны, что их нужно писать вручную. Это не так; вы можете создавать синтаксические анализаторы Java и ​​C++ очень хорошо с генераторами синтаксических анализаторов GLR.

Но на самом деле проблема не в синтаксическом анализе.

После того, как вы проанализируете, вы захотите что-то сделать с деревом AST/parse. На практике вам необходимо знать для каждого идентификатора, каково его определение и где оно используется ("разрешение имен и типов", небрежно, построение таблиц символов). Оказывается, это ОЧЕНЬ Гораздо больше работы, чем правильно разбирать синтаксический анализатор, составленный наследованием, интерфейсами, перегрузкой и шаблонами, а также тем, что семантика всего этого написана на неформальном естественном языке и распространяется на десятки и сотни страниц. языкового стандарта. C++ действительно плох здесь. Java 7 и 8 становятся довольно ужасными с этой точки зрения. (И таблицы символов не все, что вам нужно; см. Мою биографию для более длинного эссе на тему "Жизнь после разбора").

Большинство людей борются с чистым синтаксическим анализом (часто не заканчивая; проверьте SO на множество вопросов о том, как создать работающие парсеры для реальных языков), поэтому они никогда не видят жизнь после анализа , И затем мы получаем народные теоремы о том, что трудно разобрать, и нет никаких сигналов о том, что происходит после этого этапа.

Исправление синтаксиса C++ никуда вас не приведет.

Что касается изменения синтаксиса C++: вы обнаружите, что вам нужно исправить множество мест, чтобы позаботиться о множестве локальных и реальных неоднозначностей в любой грамматике C++. Если вы настаиваете, следующий список может быть хорошей отправной точкой . Я утверждаю, что нет никакого смысла делать это, если вы не являетесь комитетом по стандартам C++; если бы вы сделали это и создали компилятор, используя его, никто в здравом уме не использовал бы его. Слишком много вложено в существующие приложения C++, чтобы переключаться для удобства парней, создающих парсеры; кроме того, их боль прошла и существующие парсеры работают нормально.

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

76
Ira Baxter