% l2h ignore change { \chapter{Finding declarations in ANSI C} This code is a slight modification of some standard noweb code. It finds all the declarations (not just definitions) in the library so that {\tt noweave.vbe} can index them. <<*>>= procedure main(args) go() end <<*>>= global typespecs, storespecs, typequals, specifiers, structlike procedure postpass(name, arg) local tok static kind initial { kind := "bogus" storespecs := set(["typedef", "extern", "static", "auto", "register"]) typespecs := set(["void", "char", "float", "short", "signed", "int", "double", "long", "unsigned"]) typequals := set(["const", "volatile"]) specifiers := storespecs ++ typespecs ++ typequals structlike := set(["struct", "union", "enum"]) } case name of { "begin" : arg ? kind := tab(upto(' ')|0) "text" : arg ? { if kind ~== "code" then return if any(' \t') then return if (="#define", tab(many(' \t'))) then return wd(c_ident_token()) if find("dclproto") then return if ="}" then { if c_ident_token() == "while" then fail # don't get tripped by do { ... } while <> } else { specifier_count := 0 while ( (member(specifiers, c_ident_token())) | # swallow a specifier (member(structlike, c_ident_token()), # struct with optional tag c_ident_token() | &null) | (any(&ucase, c_ident_token())) # assume a typedef'd type, skip ) do specifier_count +:= 1 if f := scan_function(tok) then { # write(&errout, "function ", image(f), " followed by ", # image(c_token()) | "") wd(f) return } if specifier_count > 0 then {<>} } } } return end <>= while x := declarator() do { wd(x) if c_token() == "," then &null else return } <<*>>= procedure wd(x) static reserved initial reserved := set([ "asm", "auto", "break", "case", "char", "const", "continue", "default", "double", "do", "else", "enum", "extern", "float", "for", "goto", "if", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while"]) if member(reserved, x) then return return writedefn(x) end procedure prepass(name, arg) end procedure c_ident_token() static alpha, alnum initial { alpha := '_' ++ &letters; alnum := alpha ++ &digits } tab(many(' \t')) if any(alpha) then suspend tab(many(alnum)) end procedure c_token() static alpha, alnum initial { alpha := '_' ++ &letters; alnum := alpha ++ &digits } tab(many(' \t')) if any(alpha) then suspend tab(many(alnum)) else suspend move(1) end procedure scan_function() (f := c_ident_token(), ##write(&errout, " try function ", image(f)), tab(many(' \t')) | &null, any('('), *tab(bal()) > 0 | (="(", *tab(bal(',', '[{(', ')}]')) > 0, =",", optwhite(), pos(0)), ##write(&errout, " caught function trailing ", image(&subject[&pos:0])), suspend f ) end procedure optwhite() suspend tab(many(' \t')) | "" end procedure declarator() while c_token() == "*" do while member(typequals, c_token()) (c_token() == "(", d := declarator(), c_token() == ")") | (d := c_ident_token()) | fail while c_token() == ("[", "(") do (tab(bal('])','[(',')]')), c_token()) return d end @ Rest is boilerplate from noweb dist. <<*>>= procedure go() local line while line := read() do { apply(prepass, line) write(line) apply(postpass, line) } end procedure apply(pass, line) line ? (="@" & pass(tab(upto(' ')|0), if =" " then tab(0) else &null)) end @ [[indextext]] is a hack to introduce suitable ``[[@index nl]],'' but it messes up the line counts! <<*>>= procedure writedefn(defn) static indextext initial indextext := "" if /defn then *indextext > 0 & <> else { if *indextext + *defn > 65 then <> write("@index defn ", defn) indextext ||:= " " || defn } return end <>= { # write("@index nl") # don't! indextext := "" }