Здравствуйте, Aleх, Вы писали:
A>Всё-таки в результате парсинга получается одно синтаксическое дерево и все неоднозначности решаются этой эвристикой?
Нет. Эта эвристика устраняет неоднозначности присущие безлексерным парсерам (а-ля PEG) и general-парсерам (незнаю уж как по-русски назвать) вроде Earley, GLR, GLL.
A>Или же, как было написано где-то в сообщениях на форуме, парсинг может быть неоднозначным и конфликты разрешаются на стадии типизации.
Наш парсер допускает неоднозначности в которых неоднозначные конструкции имеют одинаковое количество одинаковых терминалов (токенов). В случае, если в процессе парсинга появилась два варианта разбора с разным числом терминалов или с терминалами разной длинны, то включается эта эвристика и устраняет неоднозначность в пользу более длинных терминалов или в пользу вариантов с большим числам терминалов. Это аналогично поведению лексерных LL(k)-парсеров.
A>Происходит ли типизация строго после парсинга или же она происходит в процессе?
Строго после окончания парсинга.
A>В C++ типизация, включающая в себя инстанциирование шаблонов, должна происходить в процессе синтаксического анализа.
Это не так.
A>В противном случае в результате парсинга получится, нечто малополезное, что потребует нового, но уже ручного разбора на стадии типизации. Грубо говоря получится только разметить (определить местоположение и имя) классы и функции. Но именно такая задача решается довольно простой грамматикой и это очень малая часть синтаксического анализа.
В результате получится вполне себе нормальное дерево разбора, возможно с неоднозначностями. Именно их можно разрешить отдельным проходом выполняемым более примитивными парсерами во время синтаксического анализа.
С точки зрения теории нет разницы осуществлять ли устранение неоднозначностей во время парсинга или же во время отдельного прохода.
>>Реальная информация о метаданных будет вычислена только в момент обращения к этим самым метаданным. Когда это произойдет, зависит от языка программирования. Так, для C++ это может случиться еще при парсинге (при разрешении неоднозначности), что не проблематично для C++, так как в этом языке все типы должны быть объявлены (или предекларированны) выше (заранее).
A>Проблематично. В методах внутри классов можно использовать типы объявленные далее по коду программы.
A>В процессе разбора тела методов пропускаются (в простейшем случае можно просто считать скобки) и их полный разбор происходит на следующих стадиях.
Это не проблема. Более того наш парсер при этом будет даже удобнее, так как всеми этими приседаниями просто не нужно будет заниматься.
Небольшое отступление.... Твой пример немного упрощенный по этому не совсем показывает проблему. В нем просто нет неоднозначности. Чтобы она появилась объявление inner нужно сделать указателем. Тогда будет неоднозначность между объявлением указателя и умножением. Ну, да это не так важно.
После парсинга у нас получится просто неоднозначное дерево разбора в котором будут неоднозначные конструкции будут встречаться два раза. Предположим, что это было объявление указатели, тогда в дереве разбора у нас будет стейтмент с объявлением переменной и еще один с операцией умножения.
Сразу после парсинга мы запускаем процедуру предварительной типизации на которой заполняются таблицы символов и каждому из идентификаторов добавляется информация является ли он именем типа и если да, то каким.
Следующим проходом мы производим устранение неоднозначностей с использованием таблицы символов построенной на предыдущем шаге. Просто связываем имена и если это имя типа, то отбрасываем ветвь с умножением, а если нет, ветвь с объявлением переменной.
A>В исходниках компиляторов clang и gcc это называется tentative parsing.
Вот он нам и не нужен, так как мы используем более мощный парсер.
A>Кроме отложенного разбора методов классов, может понадобиться предварительный парсинг частей выражения для most vexing parse.
Аналогично и тут. Это всего лишь неоднозначность и в стандарте С++ четко описано как ее устранять. Собственно так и поступает Clang++. О чем свидетельствует его выхлоп "parentheses were disambiguated as a function declaration".
ЗЫ
Вообще, парсинг языков вроде С++ должен радикально упроститься с использованием генерализованных парсеров (так что ли их назвать?) именно потому что не нужно никаких танцев с бубнами. Можно получить неоднозначное дерево разбора соответствующее контекстно-свободной грамматике, а потом разрешить неоднозначности использую уже полное дерево разбора.
У С++ проблемы будут совсем с дргуим. Там сложен сам процесс типизации. Причем основная сложность — вычислительная. То что нет метаданных, а есть инклюды сильно усложняет жизнь.