Git init
[external/mawk.git] / examples / decl.awk
1 #!/usr/bin/awk -f
2
3 # parse a C declaration by recursive descent
4 # based on a C program in KR ANSI edition
5 #
6 # run on a C file it finds the declarations
7 #
8 # restrictions: one declaration per line
9 #               doesn't understand struct {...}
10 #               makes assumptions about type names
11 #
12 #
13 #  some awks need double escapes on strings used as
14 #  regular expressions.  If not run on mawk, use gdecl.awk
15
16
17 ################################################
18 #   lexical scanner -- gobble()
19 #   input : string s -- treated as a regular expression
20 #   gobble eats SPACE, then eats longest match of s off front
21 #   of global variable line.
22 #   Cuts the matched part off of line
23 #
24
25
26 function gobble(s,  x)  
27 {
28   sub( /^ /, "", line)  # eat SPACE if any
29
30   # surround s with parenthesis to make sure ^ acts on the
31   # whole thing
32
33   match(line, "^" "(" s ")")
34   x = substr(line, 1, RLENGTH)
35   line = substr(line, RLENGTH+1)
36   return x 
37 }
38
39
40 function ptr_to(n,  x)  # print "pointer to" , n times
41 { n = int(n)
42   if ( n <= 0 )  return ""
43   x = "pointer to" ; n--
44   while ( n-- )  x = x " pointer to"
45   return x
46 }
47
48
49 #recursively get a decl
50 # returns an english description of the declaration or
51 # "" if not a C declaration.
52
53 function  decl(   x, t, ptr_part)
54 {
55
56   x = gobble("[* ]+")   # get list of *** ...
57   gsub(/ /, "", x)   # remove all SPACES
58   ptr_part = ptr_to( length(x) )
59
60   # We expect to see either an identifier or '('
61   #
62
63   if ( gobble("\(") )
64   { 
65     # this is the recursive descent part
66     # we expect to match a declaration and closing ')'
67     # If not return "" to indicate  failure
68
69       if ( (x = decl()) == "" || gobble( "\)" ) == "" ) return ""
70
71   }
72   else  #  expecting an identifier
73   {
74     if ( (x = gobble(id)) == "" )  return ""
75     x = x ":"
76   }
77
78   # finally look for ()
79   # or  [ opt_size ]
80
81   while ( 1 )
82      if ( gobble( funct_mark ) )  x = x " function returning"
83      else
84      if ( t = gobble( array_mark ) )
85      { gsub(/ /, "", t)
86        x = x " array" t " of"
87      }
88      else  break
89
90
91    x = x " "  ptr_part
92    return x
93 }
94     
95
96 BEGIN { id = "[_A-Za-z][_A-Za-z0-9]*" 
97         funct_mark = "\([ \t]*\)"
98         array_mark = "\[[ \t]*[_A-Za-z0-9]*[ \t]*\]"
99
100 # I've assumed types are keywords or all CAPS or end in _t
101 # Other conventions could be added.
102
103     type0 = "int|char|short|long|double|float|void" 
104     type1 = "[_A-Z][_A-Z0-9]*"  #  types are CAPS
105     type2 = "[_A-Za-z][_A-Za-z0-9]*_t"  # end in _t
106
107     types = "(" type0 "|" type1 "|" type2 ")"
108 }
109
110
111 {   
112
113     gsub( "/\*([^*]|\*[^/])*(\*/|$)" , " ") # remove comments
114     gsub( /[ \t]+/, " ")  # squeeze white space to a single space
115
116
117     line = $0
118
119     scope = gobble( "extern|static" )
120
121     if ( type = gobble("(struct|union|enum) ") )
122                 type = type gobble(id)  #  get the tag
123     else
124     {
125
126        type = gobble("(un)?signed ") gobble( types )
127
128     }
129     
130     if ( ! type )  next
131     
132     if ( (x = decl()) && gobble( ";") )
133     {
134       x  =  x " " type
135       if ( scope )  x = x " (" scope ")"
136       gsub( /  +/, " ", x)  # 
137       print x
138     }
139
140 }