lint is divided into 3 separate programs: lint, lint1, and lint2 (the latter two programs reside in /usr/libexec). lint calls /usr/libexec/cpp to preprocess the program, then passes the output to lint1, which does most of the work. lint1 then outputs a .ln file, which is parsed by lint2 to do more holistic checks. all of this is driven by /usr/bin/lint, which is like a wrapper program. lint1 implements its own C parser. it is incapable of parsing some weird gcc things, such as __attribute__ and so on. OpenBSD's source tree already does a good job of removing gcc'isms when parsers other than gcc are detected. lint1 keeps a symbol table for the current context, which always includes global symbols for the current translation unit, as well as locals (inside a function definition). When it parses a function definition, it pushes a symbol table context onto the stack, and then pops it off when the function definition ends. lint1 does the vast majority of its checks one expression at a time. It uses the symbol table (which contains types of symbols) and almost nothing else when doing type conversions. All of the checks happen at parse time. lint1 does not really build an abstract syntax tree (AST) to represent the entire program; it only keeps track of the symbols in the current context, and some minimal information about the types of enclosing control blocks (loops, switch statements, etc). When lint1 is finished parsing an expression, you will not see any more warnings regarding that expression. $OpenBSD: README,v 1.2 2007/09/24 19:56:34 jmc Exp $