uuscan.h provides single-header low-overhead tokenless helper functions for scanning lexical elements in recursive descent parsing (with backtracking). It could be useful for small command-languages, DSL's, or other ad-hoc parsing jobs where integrating lex and yacc or other tools is too expensive and using straight strcmp's too tedious. The two main functions provided are the self-documenting accept() and expect(). Errors are typically handled by a non-local goto for instant unwinding of deeply nested parsing. Any number of application-defined terminals can be used without lookup penalty. Each terminal is processed in its own scanning function. Functions for literal matching of strings and characters are provided in uuscan.h; terminal scanning functions must be provided by the application. An example application is in example.c Read the notes in uuscan.h for more information Here's a brief overview showing a terminal T being defined and used: // define all terminal names required by app: #define UUTERMINALS X(T) ... // if terminal scan functions return a converted value such values can be // assigned to application-defined identifiers in the uu struct. define UUVAL like: #define UUVAL { int i; char *s; } #include "uuscan.h" ... // scanning function for T; this defines a function header bool __scan_T(char *lp) UUDEFINE(T) { // lp is ptr to the next non-space char of the input line to scan. // IF the text beginning at lp matches the rules for T and there are no errors // on conversion then 'return success(lp)' will update the global uu.lp pointer // to the first char after the current scan. // ELSE on any scan or conversion error 'return fail(lp)' will update // uu.lpfail where the scan failed; app parsing code will determine if // this is an error or a backtrack condition. // for error handling normally a call to uuerror(..) is made to format an // error message. uuerror() will then jump to the on_uuerror() {...} code // block where the error message can be output and a decision made to continue // or to exit(1). // assign converted or saved values to uu.i, uu.s, etc. as declared with UUVAL above // or use a second ptr-to-variable argument in accept() and expect() } ... // declare uuerror() target: on_uuerror { // report error message // either exit with error or fall through to read next line } // read loop: while (uu.line = read_next_line()) { uu.lp = uu.line; ... if (accept(T)) { ... } expect(T); } }