Разбор с помощью libclang; невозможно проанализировать определенные токены (Python в Windows)
У меня есть некоторый код (взятый и адаптированный здесь и здесь), который использует libclang для анализа исходных файлов C++ в Python (Widnows) и получения всех его операторов объявлений, как показано здесь:
import clang.cindex
def parse_decl(node):
reference_node = node.get_definition()
if node.kind.is_declaration():
print(node.kind, node.kind.name,
node.location.line, ',', node.location.column,
reference_node.displayname)
for ch in node.get_children():
parse_decl(ch)
# configure path
clang.cindex.Config.set_library_file('C:/Program Files (x86)/LLVM/bin/libclang.dll')
index = clang.cindex.Index.create()
trans_unit = index.parse(r'C:\path\to\sourcefile\test.cpp', args=['-std=c++11'])
parse_decl(trans_unit.cursor)
Для следующего исходного файла C++ (test_ok.cpp
):
/* test_ok.cpp
*/
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cmath>
#include <iomanip>
using namespace std;
int main (int argc, char *argv[]) {
int linecount = 0;
double array[1000], sum=0, median=0, add=0;
string filename;
if (argc <= 1)
{
cout << "Error: no filename specified" << endl;
return 0;
}
//program checks if a filename is specified
filename = argv[1];
ifstream myfile (filename.c_str());
if (myfile.is_open())
{
myfile >> array[linecount];
while ( myfile.good() )
{
linecount++;
myfile >> array[linecount];
}
myfile.close();
}
parse
метод анализирует как следует и выводит:
CursorKind.USING_DIRECTIVE USING_DIRECTIVE 10 , 17 std
CursorKind.FUNCTION_DECL FUNCTION_DECL 12 , 5 main(int, char **)
CursorKind.PARM_DECL PARM_DECL 12 , 15 argc
CursorKind.PARM_DECL PARM_DECL 12 , 27 argv
CursorKind.VAR_DECL VAR_DECL 13 , 7 linecount
CursorKind.VAR_DECL VAR_DECL 14 , 10 array
CursorKind.VAR_DECL VAR_DECL 14 , 23 sum
CursorKind.VAR_DECL VAR_DECL 14 , 30 median
CursorKind.VAR_DECL VAR_DECL 14 , 40 add
CursorKind.VAR_DECL VAR_DECL 15 , 10 filename
CursorKind.VAR_DECL VAR_DECL 23 , 12 myfile
Process finished with exit code 0
ОДНАКО,
для следующего исходного кода C++ (test.cpp
):
/* test.cpp
*/
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;
void readfunction(vector<double>& numbers, ifstream& myfile)
{
double number;
while (myfile >> number) {
numbers.push_back(number);}
}
double meanfunction(vector<double>& numbers)
{
double total=0;
vector<double>::const_iterator i;
for (i=numbers.begin(); i!=numbers.end(); ++i) {
total +=*i; }
return total/numbers.size();
}
разбор неполный:
CursorKind.USING_DIRECTIVE USING_DIRECTIVE 8 , 17 std
CursorKind.VAR_DECL VAR_DECL 10 , 6 readfunction
Process finished with exit code 0
анализ не может обрабатывать такие строки, как vector<double>& numbers
и т.д. и прекращает синтаксический анализ этой части кода.
Я считаю, что проблема похожа на описанную в другом вопросе SO. Я пытался явно использовать std=c++11
разбирать аргументы безуспешно. В ответе на этот вопрос (хотя это не решило проблему) использование -x c++
также предлагается, но я понятия не имею, как добавить это в моем коде выше.
Любой может указать на решение для libclang для синтаксического анализа операторов C++, как те, что в test.cpp
?
Кроме того, могу ли я сделать так, чтобы он продолжал синтаксический анализ, даже если он получит токен, который он не сможет проанализировать?
1 ответ
По умолчанию libclang не добавляет путь компиляции системы компиляции.
Обязательно проверяйте диагностику - например, сообщения об ошибках компилятора, они, как правило, указывают, как решить любые проблемы. В этом случае было бы достаточно очевидно, что существует проблема включения:
<Diagnostic severity 4, location <SourceLocation file 'test.cpp', line 3, column 10>, spelling "'iostream' file not found">
Если вы убедитесь, что libclang добавляет эти пути, он должен начать работать.
Этот вопрос включает в себя подход к решению этой проблемы. Похоже, это повторяющаяся тема в Stackru, поэтому я написал ccsyspath, чтобы помочь найти эти пути в OSX, Linux и Windows. Упрощение вашего кода немного:
import clang.cindex
clang.cindex.Config.set_library_file('C:/Program Files (x86)/LLVM/bin/libclang.dll')
import ccsyspath
index = clang.cindex.Index.create()
args = '-x c++ --std=c++11'.split()
syspath = ccsyspath.system_include_paths('clang++')
incargs = [ b'-I' + inc for inc in syspath ]
args = args + incargs
trans_unit = index.parse('test.cpp', args=args)
for node in trans_unit.cursor.walk_preorder():
if node.location.file is None:
continue
if node.location.file.name != 'test.cpp':
continue
if node.kind.is_declaration():
print(node.kind, node.location)
Где моя args
в конечном итоге:
['-x',
'c++',
'--std=c++11',
'-IC:\\Program Files (x86)\\LLVM\\bin\\..\\lib\\clang\\3.8.0\\include',
'-IC:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\include',
'-IC:\\Program Files (x86)\\Windows Kits\\8.1\\include\\shared',
'-IC:\\Program Files (x86)\\Windows Kits\\8.1\\include\\um',
'-IC:\\Program Files (x86)\\Windows Kits\\8.1\\include\\winrt']
и вывод:
(CursorKind.USING_DIRECTIVE, <SourceLocation file 'test.cpp', line 10, column 17>)
(CursorKind.FUNCTION_DECL, <SourceLocation file 'test.cpp', line 12, column 6>)
(CursorKind.PARM_DECL, <SourceLocation file 'test.cpp', line 12, column 35>)
(CursorKind.PARM_DECL, <SourceLocation file 'test.cpp', line 12, column 54>)
(CursorKind.VAR_DECL, <SourceLocation file 'test.cpp', line 15, column 14>)
(CursorKind.FUNCTION_DECL, <SourceLocation file 'test.cpp', line 21, column 8>)
(CursorKind.PARM_DECL, <SourceLocation file 'test.cpp', line 21, column 37>)
(CursorKind.VAR_DECL, <SourceLocation file 'test.cpp', line 24, column 14>)
(CursorKind.VAR_DECL, <SourceLocation file 'test.cpp', line 25, column 40>)