Skip to content

ltcmelo/psychec

Repository files navigation

C language (draft) proposal Enabling Generic Functions and Parametric Types in C; prototype available here.

Psyche-C

Psyche-C is a compiler frontend for the C language. It is designed as a library, with a focus on the implementation of static analysis tools of C programs, without requiring understanding of their build setup. Bellow are the main characteristics of Psyche-C:

  • Clean separation between the syntactic and semantic compiler phases.
  • Algorithmic and heuristic syntax disambiguation.
  • Optional type inference for missing struct, union, enum, and typedef (due to #include failures).
  • API inspired by that of the Roslyn .NET compiler and LLVM's Clang frontend.

Library and API

Psyche-C's native API is in C++, but APIs for other languages are planned.

void analyse(const SourceText& srcText, const FileInfo& fi)
{
    ParseOptions parseOpts;
    parseOpts.setAmbiguityMode(AmbiguityMode::DisambiguateAlgorithmically);

    auto tree = SyntaxTree::parseText(srcText,
                                      TextPreprocessingState::Preprocessed,
                                      TextCompleteness::Fragment,
                                      parseOpts,
                                      fi.fileName());

    auto compilation = Compilation::create("code-analysis");
    compilation->addSyntaxTree(tree.get());

    AnalysisVisitor analysis(tree.get(), compilation->semanticModel(tree.get()));
    analysis.run(tree->translationUnitRoot());
}
SyntaxVisitor::Action AnalysisVisitor::visitFunctionDefinition(const FunctionDefinitionSyntax* node) override
{
    const sym = semaModel->declaredSymbol(node);
    if (sym->kind() == SymbolKind::Function) {
        const FunctionSymbol* funSym = sym->asFunction();
        // ...
    }
    return Action::Skip;
}

The cnippet Driver

Psyche-C comes with the cnippet driver and it can be used as an ordinary parser for C snippets. For instance, if you compile the snippet below with cnippet, you'll see a diagnostic similar to the one you'd see with GCC or Clang.

void f()
{
    int ;
}
~ cnip test.c
test.c:4:4 error: declaration does not declare anything
int ;
    ^

Type Inference

Psyche-C can optionally (so far only available in the original branch) infer the missing types of a C snippet. For instance, for the snippet below, Psyche-C can infer a (compilable) declaration for T an synthesize it during compilation.

void f()
{
    T v = 0;
    v->value = 42;
    v->next = v;
}
typedef struct TYPE_2__ TYPE_1__;
struct TYPE_2__ 
{
    int value;
    struct TYPE_2__* next;
} ;
typedef TYPE_1__* T;

You might want to use this functionality to:

  • Enable, on incomplete programs, static analysis tools that require complete programs.
  • Compile a snippet (e.g. retrieved from a bug tracker) for object-code inspection.
  • Generate test-input data for a function in isolation..
  • Prototype an algorithm without specific data-structures.

Documentation and Resources

Building and Testing

Except for type inference, which is written in Haskell, Psyche-C is written in C++17; cnippet is written in Python 3.

To build:

cmake CMakeLists.txt && make -j 4

To run the tests:

./test-suite

Related Publications

Of Psyche-C itself:

That use Psyche-C: