Как объединить два AST?
Я пытаюсь реализовать инструмент для объединения различных версий исходного кода. Учитывая две версии одного и того же исходного кода, идея будет заключаться в том, чтобы проанализировать их, сгенерировать соответствующие деревья абстрактного источника (AST) и, наконец, объединить их в один выходной источник, сохраняя грамматическую согласованность - лексер и парсер являются вопросами ANTLR: Как пропустить многострочные комментарии.
Я знаю, что есть класс ParserRuleReturnScope
это помогает... но getStop()
а также getStart()
всегда возвращать ноль:-(
Вот фрагмент, который иллюстрирует, как я изменил свой perser, чтобы напечатать правила:
parser grammar CodeTableParser;
options {
tokenVocab = CodeTableLexer;
backtrack = true;
output = AST;
}
@header {
package ch.bsource.ice.parsers;
}
@members {
private void log(ParserRuleReturnScope rule) {
System.out.println("Rule: " + rule.getClass().getName());
System.out.println(" getStart(): " + rule.getStart());
System.out.println(" getStop(): " + rule.getStop());
System.out.println(" getTree(): " + rule.getTree());
}
}
parse
: codeTabHeader codeTable endCodeTable eof { log(retval); }
;
codeTabHeader
: comment CodeTabHeader^ { log(retval); }
;
...
2 ответа
Призыв к log(retval)
в вашем коде синтаксического анализатора похоже, что это произойдет в конце правила, но это не так. Вы хотите переместить звонок в @after
блок.
Я изменился log
выплюнуть сообщение, а также информацию о области и добавить вызовы к нему в моей собственной грамматике, например, так:
script
@init {log("@init", retval);}
@after {log("@after", retval);}
: statement* EOF {log("after last rule reference", retval);}
-> ^(STMTS statement*)
;
Синтаксический тестовый ввод дал следующий результат:
Logging from @init
getStart(): [@0,0:4='Print',<10>,1:0]
getStop(): null
getTree(): null
Logging from after last rule reference
getStart(): [@0,0:4='Print',<10>,1:0]
getStop(): null
getTree(): null
Logging from @after
getStart(): [@0,0:4='Print',<10>,1:0]
getStop(): [@4,15:15='<EOF>',<-1>,1:15]
getTree(): STMTS
Звонок в after
блок имеет как stop
а также tree
поля заполнены.
Я не могу сказать, поможет ли это вам с вашим инструментом слияния, но я думаю, что это, по крайней мере, поможет вам решить проблему с наполовину заполненным объектом области видимости.
Предполагая, что у вас есть AST (зачастую их трудно получить, разбор реальных языков зачастую сложнее, чем кажется), вы должны сначала определить, что у них общего, и построить отображение, собирающее эту информацию. Это не так просто, как кажется; Считаете ли вы блок кода, который был перемещен, но является тем же поддеревом, что и "общий"? Как насчет двух одинаковых поддеревьев, за исключением согласованного переименования идентификатора? Как насчет измененных комментариев? (большинство AST теряют комментарии; большинство программистов подумают, что это действительно плохая идея).
Вы можете построить вариант алгоритма "Longest Common Substring" для сравнения деревьев. Я использовал это в инструментах, которые я построил.
Наконец, после того, как вы объединили деревья, теперь вам нужно восстановить текст, в идеале сохраняя большую часть макета исходного кода. (Программисты ненавидят, когда вы изменяете макет, который они так любя производят). Таким образом, ваши AST должны собирать информацию о местоположении, а ваша регенерация должна соблюдать это там, где это возможно.