В скрипте python проверьте синтаксическую корректность кода C в формате str

#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 это вряд ли сильно поможет, поскольку в любом случае есть так много других файлов для чтения.