~ubuntu-branches/ubuntu/wily/coq-doc/wily

« back to all changes in this revision

Viewing changes to tools/coqwc.mll

  • Committer: Bazaar Package Importer
  • Author(s): Stéphane Glondu, Stéphane Glondu, Samuel Mimram
  • Date: 2010-01-07 22:50:39 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100107225039-n3cq82589u0qt0s2
Tags: 8.2pl1-1
[ Stéphane Glondu ]
* New upstream release (Closes: #563669)
  - remove patches
* Packaging overhaul:
  - use git, advertise it in Vcs-* fields of debian/control
  - use debhelper 7 and dh with override
  - use source format 3.0 (quilt)
* debian/control:
  - set Maintainer to d-o-m, set Uploaders to Sam and myself
  - add Homepage field
  - bump Standards-Version to 3.8.3
* Register PDF documentation into doc-base
* Add debian/watch
* Update debian/copyright

[ Samuel Mimram ]
* Change coq-doc's description to mention that it provides documentation in
  pdf format, not postscript, closes: #543545.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(************************************************************************)
 
2
(*  v      *   The Coq Proof Assistant  /  The Coq Development Team     *)
 
3
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
 
4
(*   \VV/  **************************************************************)
 
5
(*    //   *      This file is distributed under the terms of the       *)
 
6
(*         *       GNU Lesser General Public License Version 2.1        *)
 
7
(************************************************************************)
 
8
 
 
9
(* coqwc - counts the lines of spec, proof and comments in Coq sources
 
10
 * Copyright (C) 2003 Jean-Christophe Filli�tre *)
 
11
 
 
12
(*i $Id: coqwc.mll 9691 2007-03-08 15:29:27Z msozeau $ i*)
 
13
 
 
14
(*s {\bf coqwc.} Counts the lines of spec, proof and comments in a Coq source. 
 
15
    It assumes the files to be lexically well-formed. *)
 
16
 
 
17
(*i*){ 
 
18
open Printf
 
19
open Lexing
 
20
open Filename
 
21
(*i*)
 
22
 
 
23
(*s Command-line options. *)
 
24
 
 
25
let spec_only = ref false
 
26
let proof_only = ref false
 
27
let percentage = ref false
 
28
let skip_header = ref true
 
29
 
 
30
(*s Counters. [clines] counts the number of code lines of the current
 
31
    file, and [dlines] the number of comment lines. [tclines] and [tdlines]
 
32
    are the corresponding totals. *)
 
33
 
 
34
let slines = ref 0
 
35
let plines = ref 0
 
36
let dlines = ref 0
 
37
 
 
38
let tslines = ref 0
 
39
let tplines = ref 0
 
40
let tdlines = ref 0
 
41
 
 
42
let update_totals () =
 
43
  tslines := !tslines + !slines; 
 
44
  tplines := !tplines + !plines; 
 
45
  tdlines := !tdlines + !dlines
 
46
 
 
47
(*s The following booleans indicate whether we have seen spec, proof or
 
48
    comment so far on the current line; when a newline is reached, [newline]
 
49
    is called and updates the counters accordingly. *)
 
50
 
 
51
let seen_spec = ref false
 
52
let seen_proof = ref false
 
53
let seen_comment = ref false
 
54
 
 
55
let newline () =
 
56
  if !seen_spec then incr slines; 
 
57
  if !seen_proof then incr plines; 
 
58
  if !seen_comment then incr dlines; 
 
59
  seen_spec := false; seen_proof := false; seen_comment := false
 
60
 
 
61
let reset_counters () = 
 
62
  seen_spec := false; seen_proof := false; seen_comment := false;
 
63
  slines := 0; plines := 0; dlines := 0
 
64
 
 
65
(*s Print results. *)
 
66
 
 
67
let print_line sl pl dl fo =
 
68
  if not !proof_only then printf " %8d" sl;
 
69
  if not !spec_only then printf " %8d" pl;
 
70
  if not (!proof_only || !spec_only) then printf " %8d" dl;
 
71
  (match fo with Some f -> printf " %s" f | _ -> ());
 
72
  if !percentage then begin
 
73
    let s = sl + pl + dl in
 
74
    let p = if s > 0 then 100 * dl / s else 0 in
 
75
    printf " (%d%%)" p
 
76
  end;
 
77
  print_newline ()
 
78
 
 
79
let print_file fo = print_line !slines !plines !dlines fo
 
80
 
 
81
let print_totals () = print_line !tslines !tplines !tdlines (Some "total")
 
82
 
 
83
(*i*)}(*i*)
 
84
 
 
85
(*s Shortcuts for regular expressions. The [rcs] regular expression
 
86
    is used to skip the CVS infos possibly contained in some comments, 
 
87
    in order not to consider it as documentation. *)
 
88
 
 
89
let space = [' ' '\t' '\r']
 
90
let character =
 
91
  "'" ([^ '\\' '\''] |
 
92
       '\\' (['\\' '\'' 'n' 't' 'b' 'r'] | ['0'-'9'] ['0'-'9'] ['0'-'9'])) "'"
 
93
let rcs_keyword =
 
94
  "Author" | "Date" | "Header" | "Id" | "Name" | "Locker" | "Log" |
 
95
  "RCSfile" | "Revision" | "Source" | "State"
 
96
let rcs = "\036" rcs_keyword [^ '$']* "\036"
 
97
let stars = "(*" '*'* "*)"
 
98
let dot = '.' (' ' | '\t' | '\n' | '\r' | eof)
 
99
let proof_start =   
 
100
  "Theorem" | "Lemma" | "Fact" | "Remark" | "Goal" | "Correctness" | "Obligation" | "Next"
 
101
let proof_end =
 
102
  ("Save" | "Qed" | "Defined" | "Abort" | "Admitted") [^'.']* '.'
 
103
 
 
104
(*s [spec] scans the specification. *)
 
105
 
 
106
rule spec = parse
 
107
  | "(*"   { comment lexbuf; spec lexbuf }
 
108
  | '"'    { let n = string lexbuf in slines := !slines + n; 
 
109
             seen_spec := true; spec lexbuf }
 
110
  | '\n'   { newline (); spec lexbuf }
 
111
  | space+ | stars 
 
112
           { spec lexbuf }
 
113
  | proof_start space
 
114
           { seen_spec := true; spec_to_dot lexbuf; proof lexbuf }
 
115
  | proof_start '\n'
 
116
           { seen_spec := true; newline (); spec_to_dot lexbuf; proof lexbuf }
 
117
  | "Program"? "Definition" space
 
118
           { seen_spec := true; definition lexbuf }
 
119
  | "Program"? "Fixpoint" space
 
120
           { seen_spec := true; definition lexbuf }
 
121
  | character | _ 
 
122
           { seen_spec := true; spec lexbuf }
 
123
  | eof    { () }
 
124
 
 
125
(*s [spec_to_dot] scans a spec until a dot is reached and returns. *)
 
126
 
 
127
and spec_to_dot = parse
 
128
  | "(*"   { comment lexbuf; spec_to_dot lexbuf }
 
129
  | '"'    { let n = string lexbuf in slines := !slines + n; 
 
130
             seen_spec := true; spec_to_dot lexbuf }
 
131
  | '\n'   { newline (); spec_to_dot lexbuf }
 
132
  | dot    { () }
 
133
  | space+ | stars 
 
134
           { spec_to_dot lexbuf }
 
135
  | character | _ 
 
136
           { seen_spec := true; spec_to_dot lexbuf }
 
137
  | eof    { () }
 
138
 
 
139
(*s [definition] scans a definition; passes to [proof] is the body is 
 
140
    absent, and to [spec] otherwise *)
 
141
 
 
142
and definition = parse
 
143
  | "(*"   { comment lexbuf; definition lexbuf }
 
144
  | '"'    { let n = string lexbuf in slines := !slines + n; 
 
145
             seen_spec := true; definition lexbuf }
 
146
  | '\n'   { newline (); definition lexbuf }
 
147
  | ":="   { seen_spec := true; spec lexbuf }
 
148
  | dot    { proof lexbuf }
 
149
  | space+ | stars 
 
150
           { definition lexbuf }
 
151
  | character | _ 
 
152
           { seen_spec := true; definition lexbuf }
 
153
  | eof    { () }
 
154
 
 
155
(*s Scans a proof, then returns to [spec]. *)
 
156
 
 
157
and proof = parse
 
158
  | "(*"   { comment lexbuf; proof lexbuf }
 
159
  | '"'    { let n = string lexbuf in plines := !plines + n; 
 
160
             seen_proof := true; proof lexbuf }
 
161
  | space+ | stars 
 
162
           { proof lexbuf }
 
163
  | '\n'   { newline (); proof lexbuf }
 
164
  | "Proof" space* '.' 
 
165
           { seen_proof := true; proof lexbuf }
 
166
  | "Proof" space
 
167
           { proof_term lexbuf }
 
168
  | proof_end
 
169
           { seen_proof := true; spec lexbuf }
 
170
  | character | _ 
 
171
           { seen_proof := true; proof lexbuf }
 
172
  | eof    { () }
 
173
 
 
174
and proof_term = parse
 
175
  | "(*"   { comment lexbuf; proof_term lexbuf }
 
176
  | '"'    { let n = string lexbuf in plines := !plines + n; 
 
177
             seen_proof := true; proof_term lexbuf }
 
178
  | space+ | stars 
 
179
           { proof_term lexbuf }
 
180
  | '\n'   { newline (); proof_term lexbuf }
 
181
  | dot    { spec lexbuf }
 
182
  | character | _ 
 
183
           { seen_proof := true; proof_term lexbuf }
 
184
  | eof    { () }
 
185
 
 
186
(*s Scans a comment. *)
 
187
 
 
188
and comment = parse
 
189
  | "(*"   { comment lexbuf; comment lexbuf }
 
190
  | "*)"   { () }
 
191
  | '"'    { let n = string lexbuf in dlines := !dlines + n; 
 
192
             seen_comment := true; comment lexbuf }
 
193
  | '\n'   { newline (); comment lexbuf }
 
194
  | space+ | stars
 
195
           { comment lexbuf }
 
196
  | character | _ 
 
197
           { seen_comment := true; comment lexbuf }
 
198
  | eof    { () }
 
199
 
 
200
(*s The entry [string] reads a string until its end and returns the number
 
201
    of newlines it contains. *)
 
202
 
 
203
and string = parse
 
204
  | '"'  { 0 }
 
205
  | '\\' ('\\' | 'n' | '"') { string lexbuf }
 
206
  | '\n' { succ (string lexbuf) }
 
207
  | _    { string lexbuf }
 
208
  | eof  { 0 }
 
209
 
 
210
(*s The following entry [read_header] is used to skip the possible header at
 
211
    the beggining of files (unless option \texttt{-e} is specified).
 
212
    It stops whenever it encounters an empty line or any character outside
 
213
    a comment. In this last case, it correctly resets the lexer position
 
214
    on that character (decreasing [lex_curr_pos] by 1). *)
 
215
 
 
216
and read_header = parse
 
217
  | "(*"   { skip_comment lexbuf; skip_until_nl lexbuf; 
 
218
             read_header lexbuf }
 
219
  | "\n"   { () }
 
220
  | space+ { read_header lexbuf }
 
221
  | _      { lexbuf.lex_curr_pos <- lexbuf.lex_curr_pos - 1 }
 
222
  | eof    { () }
 
223
 
 
224
and skip_comment = parse
 
225
  | "*)" { () }
 
226
  | "(*" { skip_comment lexbuf; skip_comment lexbuf }
 
227
  | _    { skip_comment lexbuf }
 
228
  | eof  { () }
 
229
 
 
230
and skip_until_nl = parse
 
231
  | '\n' { () }
 
232
  | _    { skip_until_nl lexbuf }
 
233
  | eof  { () }
 
234
 
 
235
(*i*){(*i*)
 
236
 
 
237
(*s Processing files and channels. *)
 
238
 
 
239
let process_channel ch =
 
240
  let lb = Lexing.from_channel ch in
 
241
  reset_counters ();
 
242
  if !skip_header then read_header lb;
 
243
  spec lb
 
244
 
 
245
let process_file f =
 
246
  try
 
247
    let ch = open_in f in
 
248
    process_channel ch;
 
249
    close_in ch;
 
250
    print_file (Some f);
 
251
    update_totals ()
 
252
  with
 
253
    | Sys_error "Is a directory" -> 
 
254
        flush stdout; eprintf "coqwc: %s: Is a directory\n" f; flush stderr
 
255
    | Sys_error s -> 
 
256
        flush stdout; eprintf "coqwc: %s\n" s; flush stderr
 
257
 
 
258
(*s Parsing of the command line. *)
 
259
 
 
260
let usage () =
 
261
  prerr_endline "usage: coqwc [options] [files]";
 
262
  prerr_endline "Options are:";
 
263
  prerr_endline "  -p   print percentage of comments";
 
264
  prerr_endline "  -s   print only the spec size";
 
265
  prerr_endline "  -r   print only the proof size";
 
266
  prerr_endline "  -e   (everything) do not skip headers";
 
267
  exit 1
 
268
 
 
269
let rec parse = function
 
270
  | [] -> []
 
271
  | ("-h" | "-?" | "-help" | "--help") :: _ -> usage ()
 
272
  | ("-s" | "--spec-only") :: args -> 
 
273
      proof_only := false; spec_only := true; parse args
 
274
  | ("-r" | "--proof-only") :: args -> 
 
275
      spec_only := false; proof_only := true; parse args
 
276
  | ("-p" | "--percentage") :: args -> percentage := true; parse args
 
277
  | ("-e" | "--header") :: args -> skip_header := false; parse args
 
278
  | f :: args -> f :: (parse args)
 
279
 
 
280
(*s Main program. *)
 
281
 
 
282
let main () =
 
283
  let files = parse (List.tl (Array.to_list Sys.argv)) in
 
284
  if not (!spec_only || !proof_only) then 
 
285
    printf "     spec    proof comments\n";
 
286
  match files with
 
287
    | [] -> process_channel stdin; print_file None
 
288
    | [f] -> process_file f
 
289
    | _ -> List.iter process_file files; print_totals ()
 
290
 
 
291
let _ = Printexc.catch main ()
 
292
 
 
293
(*i*)}(*i*)
 
294
 
 
295