#python #c #clang #llvm
#python #c #лязг #llvm
Вопрос:
Обязательно в программе python и учитывая str
переменную, содержащую код C, я хочу быстро проверить, является ли этот код синтаксически правильным или нет. По сути, мне нужно только передать его через интерфейс компилятора.
Моя текущая реализация использует временный файл для сброса строки и вызывает процесс clang с подпроцессом (нерабочий код ниже, чтобы проиллюстрировать мое решение). Это очень медленно для моих нужд.
src = "int main(){printf("This is a C programn"); return 0;}"
with open(temp_file, 'w') as f:
f.write(src)
cmd = ["clang", abs_path(f), flags]
subprocess.Popen(cmd)
## etc..
Осмотревшись, я узнал о clang.cindex
модуле ( pip clang
), который я опробовал. После небольшого чтения основного модуля строки 2763-2837 (в частности, строка 2828) привели меня к выводу, что следующий фрагмент кода будет делать то, что мне нужно:
import clang.cindex
......
try:
unit = clang.cindex.TranslationUnit.from_source(temp_code_file, ##args, etc.)
print("Compiled!")
except clang.cindex.TranslationUnitLoadError:
print("Did not compile!")
Однако, похоже, что даже если исходный файл содержит очевидные синтаксические ошибки, исключение не возникает. Кто-нибудь знает, чего мне не хватает, чтобы заставить это работать?
В общем контексте любые предложения о том, как выполнить эту задачу как можно быстрее, будут более чем приветствоваться. Даже при clang.cindex
этом я не могу отказаться от записи моего кода, представленного строками, во временный файл, что может быть дополнительным накладным расходом. Написание синтаксического анализатора python может решить эту проблему, но на данный момент это излишество, независимо от того, насколько мне нужна скорость.
Комментарии:
1. не удалось быстро найти документ, но не кажется
unit
ли вам, что это может привести к успеху или неудачеfrom_source()
?2. @DanielFarrell я сделал, хотя
unit
содержит толькоIndex
объект.Index
может вызыватьparse()
, в которомTranslationUnit.from_source()
создается a . Поэтому, если я чего-то не упустил, мне кажется, что единственным взаимодействием с «ошибочным» поведением является исключение в строке 2828.3. вы видели строку 2798 «Ответственность за проверку tu.diagnostics на наличие ошибок лежит на вызывающем абоненте». где, я полагаю, tu — это TranslationUnit ?
4. @BrunoO, хороший комментарий, похоже, что итерация
diagnostics @property
выдает статус компиляции входного src. На самом деле это решение.
Ответ №1:
Сама компиляция завершается успешно, даже если в файле есть синтаксические ошибки. Рассмотрим следующий пример:
import clang.cindex
with open('broken.c', 'w') as f:
f.write('foo bar baz')
unit = clang.cindex.TranslationUnit.from_source('broken.c')
for d in unit.diagnostics:
print(d.severity, d)
Запустите его, и вы получите
3 broken.c:1:1: error: unknown type name 'foo'
3 broken.c:1:8: error: expected ';' after top level declarator
severity
Членом является an int
со значением из enum CXDiagnosticSeverity
with values
- CXDiagnostic_Ignored = 0
- CXDiagnostic_Note = 1
- CXDiagnostic_Warning = 2
- CXDiagnostic_Error = 3
- CXDiagnostic_Fatal = 4
Комментарии:
1. хороший пост, это действительно правильное решение! Спасибо. Этот ответ будет отмечен как принятый в ближайшее время, если только кто-нибудь не предложит более быстрое решение для проверки, возможно, избавившись от сброса строкового кода во временный файл.
2. @FoivosTs это вряд ли сильно поможет, поскольку в любом случае есть так много других файлов для чтения.