Hacker News new | past | comments | ask | show | jobs | submit login
SuperC: Parsing All of C by Taming the Preprocessor [pdf] (2012) (paulgazzillo.com)
95 points by g0xA52A2A 10 months ago | hide | past | favorite | 14 comments



This is way over my head, but I was reminded of The C language is purely functional by Conal Elliott: http://conal.net/blog/posts/the-c-language-is-purely-functio...



Has anyone already integrated it as a vscode extension?


Figure 1 spoke to me. It's an expanded syntax tree that branches depending on on the value of a preprocessor definition "CONFIG...X". I've often found myself doing the kind of code archeology that this paper seems to be trying to automate: exploring all the configuration possibilities implied by the codebase / build system. A C program that makes heavy use of the preprocessor is generally harder to grok by both h humans and static analysis because 1. the C preprocessor syntax is different from C, 2. the inputs are not necessarily bounded by what appears in the source files alone ("-DCONFIG...X=foo" passed in from the build system), and 3. the resulting program and its control flow may be quite different depending on preprocessor options. As a simple example embedded systems often define an "ASSERT(X)" macro as either noop, an infinite loop, a print statement or the like.

This is definitely a niche space but I see clear use for large, portable and configurable c codebases (e.g. Linux kernel, FreeRTOS) for providing better visibility into the configuration system.


You may be interested in unifdef, which selectively evaluates and removes ifdefs.

https://dotat.at/prog/unifdef/

I used it once at work for a niche usecase. It’s main use case seems to be making it easier to simplify platform-specific code when you remove support from old platforms in legacy codebases.


It seems that the use of macros/IFDEF (in any language, not just C) -- bifurcates into two distinct use-cases:

1) Platform/Processor/OS configuration/build use-cases.

(and)

2) All other use-cases that are not directly related to #1.

In other words, if you're a future language designer and you design a macro system for your language, you might wish to distinguish between configuration/platform/build related macros -- and other macros not directly related to build and configuration...

Doing that would allow one set and/or the other set to be selectively and easily evaluated back into the non-macro source of the base language -- depending on what is desired by the language user...

Anyway, an excellent link!


Fwiw, ~20 years ago my experience was that preprocessor use in open-source C code was very idiomatic, and iirc, a simple backtracking parser with idioms was sufficient to parse all I tried it against, including the linux kernel.


By the way, GNU Bison implements general LR (GLR) parsing by something that can be called "fork merge LR". The documentation states that Bison's GLR algorithm resolves ambiguities by forking parallel parses, which then merge. It's not the same as forking due to a preprocessor conditional, but worth mentioning.


I am obviously not able to understand what, specific, problem this is solving based on the title of "parsing all of C" when the preprocessor is apparently left intact by design

    static int mousedev_open(struct inode *inode, struct file *file)
    {
    int i;

    #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
    if (imajor(inode) == 10)
    i = 31;
    else
    #endif
    i = iminor(inode) - 32;

    return 0;
    }
    (b) The preprocessed source preserving all configurations
and my experience with C is that there are untold number of "unbound" tokens that are designed to be injected in by -D or auto-generated config.h files, so presumably this works closer to the "ready for compilation" phase versus something one could use to make tree-sitter better (as an example)


This looks really useful, but it seems like an uphill battle even reproducing given the lack of updates in almost the last decade.


Do you mean getting it to run on modern JVMs or that the C used in the kernel has drifted such that the technique would no longer apply?


I mean that it's often difficult to take older projects like this and properly replicate the environment with all dependencies.

The point about the C used in the kernel drifting could be relevant, but with this sort of project I'm more concerned initially with reproducing results and then moving forward.


> In exploring configuration-preserving parsing, we focus on performance.

Why, because this goose is so thoroughly cooked that all that is left is optimizing for speed?

There is a lot of misplaced focus on performance in CS academia, and also in software.

Suppose we have some accurate tool that does something useful with a C program, but it takes 5 minutes to run instead of 5 seconds. So what? Someone still wants to use it. Suppose the program is used by millions of people, and that 5 minute run only has to be repeated half a dozen times during development.

Get it right, and get it in people's hands should be the priorities, and not necessarily in that order.


This is (2012). I don't see that it has been discussed before here though. I guess it didn't make much of a splash.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: